版博士V2.0程序
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 

103 строки
2.9 KiB

  1. import os from 'node:os';
  2. import onExit from 'signal-exit';
  3. const DEFAULT_FORCE_KILL_TIMEOUT = 1000 * 5;
  4. // Monkey-patches `childProcess.kill()` to add `forceKillAfterTimeout` behavior
  5. export const spawnedKill = (kill, signal = 'SIGTERM', options = {}) => {
  6. const killResult = kill(signal);
  7. setKillTimeout(kill, signal, options, killResult);
  8. return killResult;
  9. };
  10. const setKillTimeout = (kill, signal, options, killResult) => {
  11. if (!shouldForceKill(signal, options, killResult)) {
  12. return;
  13. }
  14. const timeout = getForceKillAfterTimeout(options);
  15. const t = setTimeout(() => {
  16. kill('SIGKILL');
  17. }, timeout);
  18. // Guarded because there's no `.unref()` when `execa` is used in the renderer
  19. // process in Electron. This cannot be tested since we don't run tests in
  20. // Electron.
  21. // istanbul ignore else
  22. if (t.unref) {
  23. t.unref();
  24. }
  25. };
  26. const shouldForceKill = (signal, {forceKillAfterTimeout}, killResult) => isSigterm(signal) && forceKillAfterTimeout !== false && killResult;
  27. const isSigterm = signal => signal === os.constants.signals.SIGTERM
  28. || (typeof signal === 'string' && signal.toUpperCase() === 'SIGTERM');
  29. const getForceKillAfterTimeout = ({forceKillAfterTimeout = true}) => {
  30. if (forceKillAfterTimeout === true) {
  31. return DEFAULT_FORCE_KILL_TIMEOUT;
  32. }
  33. if (!Number.isFinite(forceKillAfterTimeout) || forceKillAfterTimeout < 0) {
  34. throw new TypeError(`Expected the \`forceKillAfterTimeout\` option to be a non-negative integer, got \`${forceKillAfterTimeout}\` (${typeof forceKillAfterTimeout})`);
  35. }
  36. return forceKillAfterTimeout;
  37. };
  38. // `childProcess.cancel()`
  39. export const spawnedCancel = (spawned, context) => {
  40. const killResult = spawned.kill();
  41. if (killResult) {
  42. context.isCanceled = true;
  43. }
  44. };
  45. const timeoutKill = (spawned, signal, reject) => {
  46. spawned.kill(signal);
  47. reject(Object.assign(new Error('Timed out'), {timedOut: true, signal}));
  48. };
  49. // `timeout` option handling
  50. export const setupTimeout = (spawned, {timeout, killSignal = 'SIGTERM'}, spawnedPromise) => {
  51. if (timeout === 0 || timeout === undefined) {
  52. return spawnedPromise;
  53. }
  54. let timeoutId;
  55. const timeoutPromise = new Promise((resolve, reject) => {
  56. timeoutId = setTimeout(() => {
  57. timeoutKill(spawned, killSignal, reject);
  58. }, timeout);
  59. });
  60. const safeSpawnedPromise = spawnedPromise.finally(() => {
  61. clearTimeout(timeoutId);
  62. });
  63. return Promise.race([timeoutPromise, safeSpawnedPromise]);
  64. };
  65. export const validateTimeout = ({timeout}) => {
  66. if (timeout !== undefined && (!Number.isFinite(timeout) || timeout < 0)) {
  67. throw new TypeError(`Expected the \`timeout\` option to be a non-negative integer, got \`${timeout}\` (${typeof timeout})`);
  68. }
  69. };
  70. // `cleanup` option handling
  71. export const setExitHandler = async (spawned, {cleanup, detached}, timedPromise) => {
  72. if (!cleanup || detached) {
  73. return timedPromise;
  74. }
  75. const removeExitHandler = onExit(() => {
  76. spawned.kill();
  77. });
  78. return timedPromise.finally(() => {
  79. removeExitHandler();
  80. });
  81. };