Comparing version 7.1.1 to 7.2.0
declare namespace fkill { | ||
interface Options { | ||
/** | ||
Force kill the process. | ||
Force kill the processes. | ||
@@ -11,2 +11,9 @@ @default false | ||
/** | ||
Force kill processes that did not exit within the given number of milliseconds. | ||
@default undefined | ||
*/ | ||
readonly forceAfterTimeout?: number; | ||
/** | ||
Kill all child processes along with the parent process. _(Windows only)_ | ||
@@ -13,0 +20,0 @@ |
98
index.js
@@ -10,2 +10,14 @@ 'use strict'; | ||
// If we check too soon, we're unlikely to see process killed so we essentially wait 3*ALIVE_CHECK_MIN_INTERVAL before the second check while producing unnecessary load. | ||
// Primitive tests show that for a process which just dies on kill on a system without much load, we can usually see the process die in 5 ms. | ||
// Checking once a second creates low enough load to not bother increasing maximum interval further, 1280 as first x to satisfy 2^^x * ALIVE_CHECK_MIN_INTERVAL > 1000. | ||
const ALIVE_CHECK_MIN_INTERVAL = 5; | ||
const ALIVE_CHECK_MAX_INTERVAL = 1280; | ||
const TASKKILL_EXIT_CODE_FOR_PROCESS_FILTERING_SIGTERM = 255; | ||
const delay = ms => new Promise(resolve => { | ||
setTimeout(resolve, ms); | ||
}); | ||
const missingBinaryError = async (command, arguments_) => { | ||
@@ -25,7 +37,13 @@ try { | ||
const windowsKill = (input, options) => { | ||
return taskkill(input, { | ||
force: options.force, | ||
tree: typeof options.tree === 'undefined' ? true : options.tree | ||
}); | ||
const windowsKill = async (input, options) => { | ||
try { | ||
return await taskkill(input, { | ||
force: options.force, | ||
tree: typeof options.tree === 'undefined' ? true : options.tree | ||
}); | ||
} catch (error) { | ||
if (!options.force && error.exitCode !== TASKKILL_EXIT_CODE_FOR_PROCESS_FILTERING_SIGTERM) { | ||
throw error; | ||
} | ||
} | ||
}; | ||
@@ -89,2 +107,22 @@ | ||
const killWithLimits = async (input, options) => { | ||
input = await parseInput(input); | ||
if (input === process.pid) { | ||
return; | ||
} | ||
if (input === 'node') { | ||
const processes = await psList(); | ||
await Promise.all(processes.map(async ps => { | ||
if (ps.name === 'node' && ps.pid !== process.pid) { | ||
await kill(ps.pid, options); | ||
} | ||
})); | ||
return; | ||
} | ||
await kill(input, options); | ||
}; | ||
const fkill = async (inputs, options = {}) => { | ||
@@ -99,19 +137,3 @@ inputs = arrify(inputs); | ||
try { | ||
input = await parseInput(input); | ||
if (input === process.pid) { | ||
return; | ||
} | ||
if (input === 'node') { | ||
const processes = await psList(); | ||
await Promise.all(processes.map(async ps => { | ||
if (ps.name === 'node' && ps.pid !== process.pid) { | ||
await kill(ps.pid, options); | ||
} | ||
})); | ||
return; | ||
} | ||
await kill(input, options); | ||
await killWithLimits(input, options); | ||
} catch (error) { | ||
@@ -134,4 +156,36 @@ if (!exists.get(input)) { | ||
} | ||
if (options.forceAfterTimeout !== undefined && !options.force) { | ||
const endTime = Date.now() + options.forceAfterTimeout; | ||
let interval = ALIVE_CHECK_MIN_INTERVAL; | ||
if (interval > options.forceAfterTimeout) { | ||
interval = options.forceAfterTimeout; | ||
} | ||
let alive = inputs; | ||
do { | ||
await delay(interval); // eslint-disable-line no-await-in-loop | ||
alive = await processExists.filterExists(alive); // eslint-disable-line no-await-in-loop | ||
interval *= 2; | ||
if (interval > ALIVE_CHECK_MAX_INTERVAL) { | ||
interval = ALIVE_CHECK_MAX_INTERVAL; | ||
} | ||
} while (Date.now() < endTime && alive.length > 0); | ||
if (alive.length > 0) { | ||
await Promise.all(alive.map(async input => { | ||
try { | ||
await killWithLimits(input, {...options, force: true}); | ||
} catch { | ||
// It's hard to filter does-not-exist kind of errors, so we ignore all of them here. | ||
// All meaningful errors should have been thrown before this operation takes place. | ||
} | ||
})); | ||
} | ||
} | ||
}; | ||
module.exports = fkill; |
{ | ||
"name": "fkill", | ||
"version": "7.1.1", | ||
"version": "7.2.0", | ||
"description": "Fabulously kill processes. Cross-platform.", | ||
@@ -5,0 +5,0 @@ "license": "MIT", |
@@ -39,3 +39,3 @@ <h1 align="center"> | ||
Returns a promise that resolves when the process is killed. | ||
Returns a promise that resolves when the processes are killed. | ||
@@ -59,4 +59,11 @@ #### input | ||
Force kill the process. | ||
Force kill the processes. | ||
##### forceAfterTimeout | ||
Type: `number`\ | ||
Default: `undefined` | ||
Force kill processes that did not exit within the given number of milliseconds. | ||
##### tree | ||
@@ -63,0 +70,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
9697
199
94