time-to-botec

Benchmark sampling in different programming languages
Log | Files | Refs | README

kill.js (3095B)


      1 'use strict';
      2 const os = require('os');
      3 const onExit = require('signal-exit');
      4 
      5 const DEFAULT_FORCE_KILL_TIMEOUT = 1000 * 5;
      6 
      7 // Monkey-patches `childProcess.kill()` to add `forceKillAfterTimeout` behavior
      8 const spawnedKill = (kill, signal = 'SIGTERM', options = {}) => {
      9 	const killResult = kill(signal);
     10 	setKillTimeout(kill, signal, options, killResult);
     11 	return killResult;
     12 };
     13 
     14 const 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 
     33 const shouldForceKill = (signal, {forceKillAfterTimeout}, killResult) => {
     34 	return isSigterm(signal) && forceKillAfterTimeout !== false && killResult;
     35 };
     36 
     37 const isSigterm = signal => {
     38 	return signal === os.constants.signals.SIGTERM ||
     39 		(typeof signal === 'string' && signal.toUpperCase() === 'SIGTERM');
     40 };
     41 
     42 const 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()`
     55 const spawnedCancel = (spawned, context) => {
     56 	const killResult = spawned.kill();
     57 
     58 	if (killResult) {
     59 		context.isCanceled = true;
     60 	}
     61 };
     62 
     63 const 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
     69 const 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 
     88 const 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
     95 const 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 
    109 module.exports = {
    110 	spawnedKill,
    111 	spawnedCancel,
    112 	setupTimeout,
    113 	validateTimeout,
    114 	setExitHandler
    115 };