source: frontend/node_modules/execa/lib/kill.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 11 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 3.0 KB
Line 
1'use strict';
2const os = require('os');
3const onExit = require('signal-exit');
4
5const DEFAULT_FORCE_KILL_TIMEOUT = 1000 * 5;
6
7// Monkey-patches `childProcess.kill()` to add `forceKillAfterTimeout` behavior
8const spawnedKill = (kill, signal = 'SIGTERM', options = {}) => {
9 const killResult = kill(signal);
10 setKillTimeout(kill, signal, options, killResult);
11 return killResult;
12};
13
14const setKillTimeout = (kill, signal, options, killResult) => {
15 if (!shouldForceKill(signal, options, killResult)) {
16 return;
17 }
18
19 const timeout = getForceKillAfterTimeout(options);
20 const t = setTimeout(() => {
21 kill('SIGKILL');
22 }, timeout);
23
24 // Guarded because there's no `.unref()` when `execa` is used in the renderer
25 // process in Electron. This cannot be tested since we don't run tests in
26 // Electron.
27 // istanbul ignore else
28 if (t.unref) {
29 t.unref();
30 }
31};
32
33const shouldForceKill = (signal, {forceKillAfterTimeout}, killResult) => {
34 return isSigterm(signal) && forceKillAfterTimeout !== false && killResult;
35};
36
37const isSigterm = signal => {
38 return signal === os.constants.signals.SIGTERM ||
39 (typeof signal === 'string' && signal.toUpperCase() === 'SIGTERM');
40};
41
42const getForceKillAfterTimeout = ({forceKillAfterTimeout = true}) => {
43 if (forceKillAfterTimeout === true) {
44 return DEFAULT_FORCE_KILL_TIMEOUT;
45 }
46
47 if (!Number.isFinite(forceKillAfterTimeout) || forceKillAfterTimeout < 0) {
48 throw new TypeError(`Expected the \`forceKillAfterTimeout\` option to be a non-negative integer, got \`${forceKillAfterTimeout}\` (${typeof forceKillAfterTimeout})`);
49 }
50
51 return forceKillAfterTimeout;
52};
53
54// `childProcess.cancel()`
55const spawnedCancel = (spawned, context) => {
56 const killResult = spawned.kill();
57
58 if (killResult) {
59 context.isCanceled = true;
60 }
61};
62
63const timeoutKill = (spawned, signal, reject) => {
64 spawned.kill(signal);
65 reject(Object.assign(new Error('Timed out'), {timedOut: true, signal}));
66};
67
68// `timeout` option handling
69const setupTimeout = (spawned, {timeout, killSignal = 'SIGTERM'}, spawnedPromise) => {
70 if (timeout === 0 || timeout === undefined) {
71 return spawnedPromise;
72 }
73
74 let timeoutId;
75 const timeoutPromise = new Promise((resolve, reject) => {
76 timeoutId = setTimeout(() => {
77 timeoutKill(spawned, killSignal, reject);
78 }, timeout);
79 });
80
81 const safeSpawnedPromise = spawnedPromise.finally(() => {
82 clearTimeout(timeoutId);
83 });
84
85 return Promise.race([timeoutPromise, safeSpawnedPromise]);
86};
87
88const validateTimeout = ({timeout}) => {
89 if (timeout !== undefined && (!Number.isFinite(timeout) || timeout < 0)) {
90 throw new TypeError(`Expected the \`timeout\` option to be a non-negative integer, got \`${timeout}\` (${typeof timeout})`);
91 }
92};
93
94// `cleanup` option handling
95const setExitHandler = async (spawned, {cleanup, detached}, timedPromise) => {
96 if (!cleanup || detached) {
97 return timedPromise;
98 }
99
100 const removeExitHandler = onExit(() => {
101 spawned.kill();
102 });
103
104 return timedPromise.finally(() => {
105 removeExitHandler();
106 });
107};
108
109module.exports = {
110 spawnedKill,
111 spawnedCancel,
112 setupTimeout,
113 validateTimeout,
114 setExitHandler
115};
Note: See TracBrowser for help on using the repository browser.