Can I invoke function before killing Express server? [duplicate] - javascript
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 this:
process.on('exit', function (){
console.log('Goodbye!');
});
I started the process, killed it, and nothing happened. I started it again, pressed Ctrl+C, and still nothing happened...
UPDATE:
You can register a handler for `process.on('exit')` and in any other case(`SIGINT` or unhandled exception) to call `process.exit()`
process.stdin.resume();//so the program will not close instantly
function exitHandler(options, exitCode) {
if (options.cleanup) console.log('clean');
if (exitCode || exitCode === 0) console.log(exitCode);
if (options.exit) process.exit();
}
//do something when app is closing
process.on('exit', exitHandler.bind(null,{cleanup:true}));
//catches ctrl+c event
process.on('SIGINT', exitHandler.bind(null, {exit:true}));
// catches "kill pid" (for example: nodemon restart)
process.on('SIGUSR1', exitHandler.bind(null, {exit:true}));
process.on('SIGUSR2', exitHandler.bind(null, {exit:true}));
//catches uncaught exceptions
process.on('uncaughtException', exitHandler.bind(null, {exit:true}));
This only works if you call synchronous code inside the handler, otherwise it will call the handler indefinitely
The script below allows having a single handler for all exit conditions. It uses an app specific callback function to perform custom cleanup code.
cleanup.js
// Object to capture process exits and call app specific cleanup function
function noOp() {};
exports.Cleanup = function Cleanup(callback) {
// attach user callback to the process event emitter
// if no callback, it will still exit gracefully on Ctrl-C
callback = callback || noOp;
process.on('cleanup',callback);
// do app specific cleaning before exiting
process.on('exit', function () {
process.emit('cleanup');
});
// catch ctrl+c event and exit normally
process.on('SIGINT', function () {
console.log('Ctrl-C...');
process.exit(2);
});
//catch uncaught exceptions, trace, then exit normally
process.on('uncaughtException', function(e) {
console.log('Uncaught Exception...');
console.log(e.stack);
process.exit(99);
});
};
This code intercepts uncaught exceptions, Ctrl+C and normal exit events. It then calls a single optional user cleanup callback function before exiting, handling all exit conditions with a single object.
The module simply extends the process object instead of defining another event emitter. Without an app specific callback the cleanup defaults to a no op function. This was sufficient for my use where child processes were left running when exiting by Ctrl+C.
You can easily add other exit events such as SIGHUP as desired. Note: per NodeJS manual, SIGKILL cannot have a listener. The test code below demonstrates various ways of using cleanup.js
// test cleanup.js on version 0.10.21
// loads module and registers app specific cleanup callback...
var cleanup = require('./cleanup').Cleanup(myCleanup);
//var cleanup = require('./cleanup').Cleanup(); // will call noOp
// defines app specific callback...
function myCleanup() {
console.log('App specific cleanup code...');
};
// All of the following code is only needed for test demo
// Prevents the program from closing instantly
process.stdin.resume();
// Emits an uncaught exception when called because module does not exist
function error() {
console.log('error');
var x = require('');
};
// Try each of the following one at a time:
// Uncomment the next line to test exiting on an uncaught exception
//setTimeout(error,2000);
// Uncomment the next line to test exiting normally
//setTimeout(function(){process.exit(3)}, 2000);
// Type Ctrl-C to test forced exit
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));
})
"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.
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
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
})
async-exit-hook seems to be the most up-to-date solution for handling this problem. It's a forked/re-written version of exit-hook that supports async code before exiting.
I need to do an asynchronous cleanup action on exit, none of the answers in this question worked for me.
So I tried it myself, and finally found this:
process.once('uncaughtException', async () => {
await cleanup()
process.exit(0)
})
process.once('SIGINT', () => { throw new Error() })
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.
I would like to route all other exiting codes to 'exit' code.
const others = [`SIGINT`, `SIGUSR1`, `SIGUSR2`, `uncaughtException`, `SIGTERM`]
others.forEach((eventType) => {
process.on(eventType, exitRouter.bind(null, { exit: true }));
})
What the exitRouter does is calling process.exit()
function exitRouter(options, exitCode) {
if (exitCode || exitCode === 0) console.log(`ExitCode ${exitCode}`);
if (options.exit) process.exit();
}
On 'exit', handle the clean up with a new function
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.
io.js has an exit and a beforeExit event, which do what you want.
In the case where the process was spawned by another node process, like:
var child = spawn('gulp', ['watch'], {
stdio: 'inherit',
});
And you try to kill it later, via:
child.kill();
This is how you handle the event [on the child]:
process.on('SIGTERM', function() {
console.log('Goodbye!');
});
Here's a nice hack for windows
process.on('exit', async () => {
require('fs').writeFileSync('./tmp.js', 'crash', 'utf-8')
});
Related
Node doesn't exit automatically once a listener is set on stdin
Node.js doesn't exit automatically once a listener is set on process.stdin, even if that listener is later removed. Example: const listener = ()=>{}; process.stdin.on("data", listener); process.stdin.off("data", listener);
If you have a live listener for incoming data on stdin and that stream stays open (isn't naturally closed by coming to the end of its source), then node.js has no idea whether there is more data that may be coming or not so it keeps the process alive. Here are several things you can do to get the app to shutdown: Call process.exit(0) to manually shut it down. Call process.stdin.unref() to tell nodejs not to wait for this stream. Call process.stdin.pause(). It appears that once you've attached the data event handler, removing it doesn't allow the app to exit (per some reports I read) so you have to resort to one of these other options. FYI, here's a little test app where you can experiment with what causes the app to shut-down or not. I've verified that all three of these options work. process.stdin.setRawMode(true); process.stdin.on('data', data => { console.log(data.toString()); if (data.toString() === 'x') { process.stdin.pause(); // will cause process to exit } }); process.stdin.resume(); process.stdout.write("Type characters, 'x' to exit\n");
For some reason, Node.js waits for process.stdin (and all other streams?) to be paused before exiting. process.stdin is initially paused, but it resumes once process.stdin.on() is called. This can be solved by calling stream.pause(), like this: const listener = ()=>{}; process.stdin.on("data", listener); process.stdin.off("data", listener); process.stdin.pause(); Note that calling stream.end() has no effect.
How can I kill a child process without the child process 'exit' event triggering?
I'm spawning a child process: child = spawn("childprocess", [], { detached: true } And I'm watching the 'exit' event with: child.on('exit', (code, signal) => { // Do stuff } When my app exits, I'm killing the child by using taskkill (because this is running on Windows): exec(`taskkill /PID ${child.pid} /F /T`, (error, stdout, stderr) => { // Do stuff } The problem is, that when the process is killed the exit event fires (understandably), but I don't want it to. Is there some way to remove the event listener? Or kill the process without triggering events? I've tried child.removeListener('exit') but that didn't work (maybe because it's an anonymous function?).
I've tried child.removeListener('exit') but that didn't work (maybe because it's an anonymous function?). Whether the function has a name or not doesn't matter. You simply need to pass the same function object to removeListener (or off): var handler = (code, signal) => {}; child.on('exit', handler); child.off('exit', handler); Or call child.removeAllListeners('exit');.
How to get event when system is about to go to sleep
Is it possible to get notified when the system is about to change its power state to sleep? Something like process.on('sleep', () => foo()) When going to sleep, the process does not get killed or exit, so answers from doing a cleanup action just before node.js exits do not suffer.
Your programm receive informations from your Operating System in linux from signals. I guess the signal you are looking for is from the following list: To handle signals in node.js here is how you do it : // Begin reading from stdin so the process does not exit. process.stdin.resume(); process.on('SIGINT', () => { console.log('Received SIGINT. Press Control-D to exit.'); }); // Using a single function to handle multiple signals function handle(signal) { console.log(`Received ${signal}`); } process.on('SIGINT', handle); process.on('SIGTERM', handle);
How would I keep the node.js process open for a second when I close it [duplicate]
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 this: process.on('exit', function (){ console.log('Goodbye!'); }); I started the process, killed it, and nothing happened. I started it again, pressed Ctrl+C, and still nothing happened...
UPDATE: You can register a handler for `process.on('exit')` and in any other case(`SIGINT` or unhandled exception) to call `process.exit()` process.stdin.resume();//so the program will not close instantly function exitHandler(options, exitCode) { if (options.cleanup) console.log('clean'); if (exitCode || exitCode === 0) console.log(exitCode); if (options.exit) process.exit(); } //do something when app is closing process.on('exit', exitHandler.bind(null,{cleanup:true})); //catches ctrl+c event process.on('SIGINT', exitHandler.bind(null, {exit:true})); // catches "kill pid" (for example: nodemon restart) process.on('SIGUSR1', exitHandler.bind(null, {exit:true})); process.on('SIGUSR2', exitHandler.bind(null, {exit:true})); //catches uncaught exceptions process.on('uncaughtException', exitHandler.bind(null, {exit:true})); This only works if you call synchronous code inside the handler, otherwise it will call the handler indefinitely
The script below allows having a single handler for all exit conditions. It uses an app specific callback function to perform custom cleanup code. cleanup.js // Object to capture process exits and call app specific cleanup function function noOp() {}; exports.Cleanup = function Cleanup(callback) { // attach user callback to the process event emitter // if no callback, it will still exit gracefully on Ctrl-C callback = callback || noOp; process.on('cleanup',callback); // do app specific cleaning before exiting process.on('exit', function () { process.emit('cleanup'); }); // catch ctrl+c event and exit normally process.on('SIGINT', function () { console.log('Ctrl-C...'); process.exit(2); }); //catch uncaught exceptions, trace, then exit normally process.on('uncaughtException', function(e) { console.log('Uncaught Exception...'); console.log(e.stack); process.exit(99); }); }; This code intercepts uncaught exceptions, Ctrl+C and normal exit events. It then calls a single optional user cleanup callback function before exiting, handling all exit conditions with a single object. The module simply extends the process object instead of defining another event emitter. Without an app specific callback the cleanup defaults to a no op function. This was sufficient for my use where child processes were left running when exiting by Ctrl+C. You can easily add other exit events such as SIGHUP as desired. Note: per NodeJS manual, SIGKILL cannot have a listener. The test code below demonstrates various ways of using cleanup.js // test cleanup.js on version 0.10.21 // loads module and registers app specific cleanup callback... var cleanup = require('./cleanup').Cleanup(myCleanup); //var cleanup = require('./cleanup').Cleanup(); // will call noOp // defines app specific callback... function myCleanup() { console.log('App specific cleanup code...'); }; // All of the following code is only needed for test demo // Prevents the program from closing instantly process.stdin.resume(); // Emits an uncaught exception when called because module does not exist function error() { console.log('error'); var x = require(''); }; // Try each of the following one at a time: // Uncomment the next line to test exiting on an uncaught exception //setTimeout(error,2000); // Uncomment the next line to test exiting normally //setTimeout(function(){process.exit(3)}, 2000); // Type Ctrl-C to test forced exit
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)); })
"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.
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
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 })
async-exit-hook seems to be the most up-to-date solution for handling this problem. It's a forked/re-written version of exit-hook that supports async code before exiting.
I need to do an asynchronous cleanup action on exit, none of the answers in this question worked for me. So I tried it myself, and finally found this: process.once('uncaughtException', async () => { await cleanup() process.exit(0) }) process.once('SIGINT', () => { throw new Error() })
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. I would like to route all other exiting codes to 'exit' code. const others = [`SIGINT`, `SIGUSR1`, `SIGUSR2`, `uncaughtException`, `SIGTERM`] others.forEach((eventType) => { process.on(eventType, exitRouter.bind(null, { exit: true })); }) What the exitRouter does is calling process.exit() function exitRouter(options, exitCode) { if (exitCode || exitCode === 0) console.log(`ExitCode ${exitCode}`); if (options.exit) process.exit(); } On 'exit', handle the clean up with a new function 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.
io.js has an exit and a beforeExit event, which do what you want.
In the case where the process was spawned by another node process, like: var child = spawn('gulp', ['watch'], { stdio: 'inherit', }); And you try to kill it later, via: child.kill(); This is how you handle the event [on the child]: process.on('SIGTERM', function() { console.log('Goodbye!'); });
Here's a nice hack for windows process.on('exit', async () => { require('fs').writeFileSync('./tmp.js', 'crash', 'utf-8') });
Cucumber-Protractor tests skipping over assertions, falsely passing
So I am brand new at Javascript, my only language before this was Ruby. I have written API tests with Cucumber and Ruby for years, but now I am trying to figure out UI tests for an angular app using Protractor and Cucumber.js. I have the framework set up and the test steps run are passing, but falsely so. Here is a snippet of my step definitions, with a few edits to change data in assertions and the string for the assertion is intentionally wrong to trigger a failure. They run and are passing, but only because it ignores the assertion. I don't see it actually doing anything in the browser, but if I put in console.log messages I do see them in the console. However, if I comment out the last callback, then I can see it run in the browser and it actually checks the assertions and fails as it should. Cucumber doesn't require callbacks, and removing them results in it running in exactly the same way... only I can't comment out a callback of course and watch it run like I mentioned above. And if I don't put that timeout in the first step, then the whole thing errors out at the first step with "Error: function timed out after 5000 milliseconds" Why?!? Thanks!! Protractor 5.3.0 with Cucumber 4.0.0 and protractor-cucumber-framework 4.2.0 Given('I am on the home page', {timeout: 30000}, (callback) => { browser.waitForAngularEnabled(false); browser.get(browser.params.env.int).then(callback); }); Then('the log in form is displayed', callback => { expect(element(by.id('email')).isPresent()).to.eventually.be.true; expect(element(by.id('password')).isPresent()).to.eventually.be.true; callback(); }); When('I enter my user name', callback => { element(by.name('email')).sendKeys('my_addy#example.com'); expect(element(by.id('email')).getAttribute('value')).to.eventually.equal('something that does match'); callback(); }); When('I enter my password', callback => { element(by.name('password')).sendKeys('blah'); callback(); }); When('I click the log in button', callback => { element(by.buttonText('Log In')).click(); callback(); }); Then('I am on the X page', callback => { expect(browser.getCurrentUrl()).to.eventually.contains('Y'); // callback(); });
1) For issue: "Error: function timed out after 5000 milliseconds This is due to your step definition function execution time duration exceeds the default timeout: 5 secs. You can change this time out globally by following my another post, or as you did add timeout only on needed step definition functions individually. 2) For Cucumber callback issue, You can choose to use callback, or choose to return a promise likely in each step definition function. I prefer the latter approach. var { Given, Then, When } = require("cucumber"); Given(/^open cucumberjs github page$/, ()=> { browser.get("https://github.com/cucumber/cucumber-js"); return expect(browser.getTitle()).to.eventually .equal("cucumber/cucumber-js: Cucumber for JavaScript"); }); When('I enter my password', ()=> { return element(by.name('password')).sendKeys('blah'); }); When('I click the log in button', ()=> { return element(by.buttonText('Log In')).click(); }); More code example, you can find from my example project here