cleankill
Advanced tools
Comparing version 1.0.3 to 2.0.0
@@ -8,14 +8,20 @@ /** | ||
*/ | ||
export declare type Handler = (doneHandling: () => void) => void; | ||
export declare type Handler = () => Promise<void>; | ||
/** | ||
* Register a handler to occur on SIGINT. All handlers are passed a callback, | ||
* and the process will be terminated once all handlers complete. | ||
* Register a handler to occur on SIGINT. The handler must return a promise if | ||
* it has any asynchronous work to do. The process will be terminated once | ||
* all handlers complete. If a handler throws or the promise it returns rejects | ||
* then the process will be terminated immediately. | ||
*/ | ||
export declare function onInterrupt(handler: Handler): void; | ||
/** | ||
* Waits for all promises to settle, then rejects with the first error, if any. | ||
*/ | ||
export declare function promiseAllStrict(promises: Promise<any>[]): Promise<void>; | ||
/** | ||
* Call all interrupt handlers, and call the callback when they all complete. | ||
* | ||
* Removes the list of interrupt handlers. | ||
* Clears the list of interrupt handlers. | ||
*/ | ||
export declare function close(done: () => void): void; | ||
export declare function close(): Promise<void>; | ||
/** | ||
@@ -25,3 +31,4 @@ * Calls all interrupt handlers, then exits with exit code 0. | ||
* If called more than once it skips waiting for the interrupt handlers to | ||
* finish and exits with exit code 1. | ||
* finish and exits with exit code 1. If there are any errors with interrupt | ||
* handlers, the process exits immediately with exit code 2. | ||
* | ||
@@ -28,0 +35,0 @@ * This function is called when a SIGINT is received. |
69
index.js
@@ -11,6 +11,16 @@ /** | ||
'use strict'; | ||
var interruptHandlers = []; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments)).next()); | ||
}); | ||
}; | ||
const interruptHandlers = []; | ||
/** | ||
* Register a handler to occur on SIGINT. All handlers are passed a callback, | ||
* and the process will be terminated once all handlers complete. | ||
* Register a handler to occur on SIGINT. The handler must return a promise if | ||
* it has any asynchronous work to do. The process will be terminated once | ||
* all handlers complete. If a handler throws or the promise it returns rejects | ||
* then the process will be terminated immediately. | ||
*/ | ||
@@ -22,22 +32,29 @@ function onInterrupt(handler) { | ||
/** | ||
* Waits for all promises to settle, then rejects with the first error, if any. | ||
*/ | ||
function promiseAllStrict(promises) { | ||
return __awaiter(this, void 0, Promise, function* () { | ||
let errors = yield Promise.all(promises.map((p) => p.then(() => null, (e) => e))); | ||
let firstError = errors.find((e) => e != null); | ||
if (firstError) { | ||
throw firstError; | ||
} | ||
}); | ||
} | ||
exports.promiseAllStrict = promiseAllStrict; | ||
/** | ||
* Call all interrupt handlers, and call the callback when they all complete. | ||
* | ||
* Removes the list of interrupt handlers. | ||
* Clears the list of interrupt handlers. | ||
*/ | ||
function close(done) { | ||
var numComplete = 0; | ||
// You could cheat by calling callbacks multiple times, but that's your bug! | ||
var total = interruptHandlers.length; | ||
interruptHandlers.forEach(function (handler) { | ||
handler(function () { | ||
numComplete = numComplete + 1; | ||
if (numComplete === total) { | ||
done(); | ||
} | ||
}); | ||
function close() { | ||
return __awaiter(this, void 0, Promise, function* () { | ||
const promises = interruptHandlers.map((handler) => handler()); | ||
// Empty the array in place. Looks weird, totally works. | ||
interruptHandlers.length = 0; | ||
yield promiseAllStrict(promises); | ||
}); | ||
interruptHandlers = []; | ||
} | ||
exports.close = close; | ||
var interrupted = false; | ||
let interrupted = false; | ||
/** | ||
@@ -47,3 +64,4 @@ * Calls all interrupt handlers, then exits with exit code 0. | ||
* If called more than once it skips waiting for the interrupt handlers to | ||
* finish and exits with exit code 1. | ||
* finish and exits with exit code 1. If there are any errors with interrupt | ||
* handlers, the process exits immediately with exit code 2. | ||
* | ||
@@ -53,13 +71,12 @@ * This function is called when a SIGINT is received. | ||
function interrupt() { | ||
if (interruptHandlers.length === 0) { | ||
return process.exit(0); | ||
} | ||
if (interrupted) { | ||
console.log('\nKilling process with extreme prejudice'); | ||
console.log('\nGot multiple interrupts, exiting immediately!'); | ||
return process.exit(1); | ||
} | ||
else { | ||
interrupted = true; | ||
} | ||
close(function () { return process.exit(0); }); | ||
interrupted = true; | ||
close().then(() => process.exit(0), (error) => { | ||
error = error || 'cleankill interrupt handler failed without a message'; | ||
console.error(error.stack || error.message || error); | ||
process.exit(2); | ||
}); | ||
console.log('\nShutting down. Press ctrl-c again to kill immediately.'); | ||
@@ -66,0 +83,0 @@ } |
63
index.ts
@@ -17,14 +17,14 @@ /** | ||
// TODO(rictic): convert this library to promises. | ||
/** | ||
* The type of a cleankill interrupt handler. | ||
*/ | ||
export type Handler = (doneHandling: () => void) => void; | ||
export type Handler = () => Promise<void>; | ||
let interruptHandlers: Handler[] = []; | ||
const interruptHandlers: Handler[] = []; | ||
/** | ||
* Register a handler to occur on SIGINT. All handlers are passed a callback, | ||
* and the process will be terminated once all handlers complete. | ||
* Register a handler to occur on SIGINT. The handler must return a promise if | ||
* it has any asynchronous work to do. The process will be terminated once | ||
* all handlers complete. If a handler throws or the promise it returns rejects | ||
* then the process will be terminated immediately. | ||
*/ | ||
@@ -36,19 +36,25 @@ export function onInterrupt(handler: Handler): void { | ||
/** | ||
* Waits for all promises to settle, then rejects with the first error, if any. | ||
*/ | ||
export async function promiseAllStrict( | ||
promises: Promise<any>[]): Promise<void> { | ||
let errors = await Promise.all( | ||
promises.map((p) => p.then(() => null, (e) => e))); | ||
let firstError = errors.find((e) => e != null); | ||
if (firstError) { | ||
throw firstError; | ||
} | ||
} | ||
/** | ||
* Call all interrupt handlers, and call the callback when they all complete. | ||
* | ||
* Removes the list of interrupt handlers. | ||
* Clears the list of interrupt handlers. | ||
*/ | ||
export function close(done: () => void): void { | ||
let numComplete = 0; | ||
// You could cheat by calling callbacks multiple times, but that's your bug! | ||
let total = interruptHandlers.length; | ||
interruptHandlers.forEach((handler) => { | ||
handler(() => { | ||
numComplete = numComplete + 1; | ||
if (numComplete === total) { | ||
done(); | ||
} | ||
}); | ||
}); | ||
interruptHandlers = []; | ||
export async function close(): Promise<void> { | ||
const promises = interruptHandlers.map((handler) => handler()); | ||
// Empty the array in place. Looks weird, totally works. | ||
interruptHandlers.length = 0; | ||
await promiseAllStrict(promises); | ||
} | ||
@@ -62,3 +68,4 @@ | ||
* If called more than once it skips waiting for the interrupt handlers to | ||
* finish and exits with exit code 1. | ||
* finish and exits with exit code 1. If there are any errors with interrupt | ||
* handlers, the process exits immediately with exit code 2. | ||
* | ||
@@ -68,13 +75,13 @@ * This function is called when a SIGINT is received. | ||
export function interrupt(): void { | ||
if (interruptHandlers.length === 0) { | ||
return process.exit(0); | ||
} | ||
if (interrupted) { | ||
console.log('\nKilling process with extreme prejudice'); | ||
console.log('\nGot multiple interrupts, exiting immediately!'); | ||
return process.exit(1); | ||
} else { | ||
interrupted = true; | ||
} | ||
interrupted = true; | ||
close(() => process.exit(0)); | ||
close().then(() => process.exit(0), (error) => { | ||
error = error || 'cleankill interrupt handler failed without a message'; | ||
console.error(error.stack || error.message || error); | ||
process.exit(2); | ||
}); | ||
console.log('\nShutting down. Press ctrl-c again to kill immediately.'); | ||
@@ -81,0 +88,0 @@ } |
{ | ||
"name": "cleankill", | ||
"version": "1.0.3", | ||
"version": "2.0.0", | ||
"description": "Hook SIGINT and cleanly shut down your async code", | ||
@@ -19,3 +19,4 @@ "homepage": "https://github.com/PolymerLabs/cleankill", | ||
}, | ||
"typings": "./index.d.ts" | ||
"typings": "./index.d.ts", | ||
"engine": ">=4" | ||
} |
@@ -16,5 +16,7 @@ # Cleankill | ||
```js | ||
cleankill.onInterrupt(function(done) { | ||
// do things. | ||
done(); | ||
cleankill.onInterrupt(() => { | ||
return new Promise((resolve) => { | ||
// do things. | ||
resolve(); | ||
}); | ||
}); | ||
@@ -26,5 +28,5 @@ ``` | ||
```js | ||
cleankill.close(function() { | ||
cleankill.close().then(() => { | ||
// All handlers have cleaned things up. | ||
}); | ||
``` |
{ | ||
"compilerOptions": { | ||
"target": "es5", | ||
"target": "es6", | ||
"module": "commonjs", | ||
@@ -5,0 +5,0 @@ "moduleResolution": "node", |
@@ -5,4 +5,4 @@ { | ||
"globalDependencies": { | ||
"node": "registry:env/node#0.10.0+20160622202520" | ||
"node": "registry:env/node#4.0.0+20160622202520" | ||
} | ||
} |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
12438
285
31
1