I want to tell Node.js to always do something just before it exits, for whatever reason — Ctrl+C, an exception, or any other reason.
I tried th
"exit" is an event that gets triggered when node finish it's event loop internally, it's not triggered when you terminate the process externally.
What you're looking for is executing something on a SIGINT.
The docs at http://nodejs.org/api/process.html#process_signal_events give an example:
Example of listening for SIGINT:
// Start reading from stdin so we don't exit.
process.stdin.resume();
process.on('SIGINT', function () {
console.log('Got SIGINT. Press Control-D to exit.');
});
Note: this seems to interrupt the sigint and you would need to call process.exit() when you finish with your code.
io.js has an exit and a beforeExit event, which do what you want.
function fnAsyncTest(callback) {
require('fs').writeFile('async.txt', 'bye!', callback);
}
function fnSyncTest() {
for (var i = 0; i < 10; i++) {}
}
function killProcess() {
if (process.exitTimeoutId) {
return;
}
process.exitTimeoutId = setTimeout(() => process.exit, 5000);
console.log('process will exit in 5 seconds');
fnAsyncTest(function() {
console.log('async op. done', arguments);
});
if (!fnSyncTest()) {
console.log('sync op. done');
}
}
// https://nodejs.org/api/process.html#process_signal_events
process.on('SIGTERM', killProcess);
process.on('SIGINT', killProcess);
process.on('uncaughtException', function(e) {
console.log('[uncaughtException] app will be terminated: ', e.stack);
killProcess();
/**
* @https://nodejs.org/api/process.html#process_event_uncaughtexception
*
* 'uncaughtException' should be used to perform synchronous cleanup before shutting down the process.
* It is not safe to resume normal operation after 'uncaughtException'.
* If you do use it, restart your application after every unhandled exception!
*
* You have been warned.
*/
});
console.log('App is running...');
console.log('Try to press CTRL+C or SIGNAL the process with PID: ', process.pid);
process.stdin.resume();
// just for testing
After playing around with other answer, here is my solution for this task. Implementing this way helps me centralize cleanup in one place, preventing double handling the cleanup.
const others = [`SIGINT`, `SIGUSR1`, `SIGUSR2`, `uncaughtException`, `SIGTERM`]
others.forEach((eventType) => {
process.on(eventType, exitRouter.bind(null, { exit: true }));
})
function exitRouter(options, exitCode) {
if (exitCode || exitCode === 0) console.log(`ExitCode ${exitCode}`);
if (options.exit) process.exit();
}
function exitHandler(exitCode) {
console.log(`ExitCode ${exitCode}`);
console.log('Exiting finally...')
}
process.on('exit', exitHandler)
For the demo purpose, this is link to my gist. In the file, i add a setTimeout to fake the process running.
If you run node node-exit-demo.js
and do nothing, then after 2 seconds, you see the log:
The service is finish after a while.
ExitCode 0
Exiting finally...
Else if before the service finish, you terminate by ctrl+C
, you'll see:
^CExitCode SIGINT
ExitCode 0
Exiting finally...
What happened is the Node process exited initially with code SIGINT, then it routes to process.exit() and finally exited with exit code 0.
Just wanted to mention death
package here: https://github.com/jprichardson/node-death
Example:
var ON_DEATH = require('death')({uncaughtException: true}); //this is intentionally ugly
ON_DEATH(function(signal, err) {
//clean up code here
})
This catches every exit event I can find that can be handled. Seems quite reliable and clean so far.
[`exit`, `SIGINT`, `SIGUSR1`, `SIGUSR2`, `uncaughtException`, `SIGTERM`].forEach((eventType) => {
process.on(eventType, cleanUpServer.bind(null, eventType));
})