Reputation: 30232
I need to do some useful things when my Express.js service is stopped by SIGINT
. Using Express.js version 3.0.6, I understand that this should work:
var express = require('express');
var app = express();
var server = app.listen(3000);
process.on('SIGINT', function() {
console.log('Do something useful here.');
server.close();
});
But the process doesn't give me back the Bash prompt unless I issue SIGINT
(Control-C) twice:
$ node problem.js
^CDo something useful here.
^CDo something useful here.
net.js:1046
throw new Error('Not running');
^
Error: Not running
at Server.close (net.js:1046:11)
at process.<anonymous> (/path/to/problem.js:8:10)
at process.EventEmitter.emit (events.js:93:17)
at SignalWatcher.startup.processSignalHandlers.process.on.process.addListener.w.callback (node.js:486:45)
$
One more caveat. If I start this Express.js service and don't send any requests then SIGINT
terminates properly.
Clearly there is something fundamental that I'm missing here?
Upvotes: 35
Views: 34210
Reputation: 179717
By catching the SIGINT
handler, you are preventing the default behaviour, which is to quit the process. When you use Ctrl+C
the second time, the process dies because server.close
throws an uncaught exception.
Just add a process.exit()
to the end of your SIGINT
handler to quit the process gracefully.
Upvotes: 48
Reputation: 828
I am using this code:
server.close(() => {
process.exit(0)
})
Upvotes: 8
Reputation: 903
Resurrecting an oldie since the question is not completely (or correctly) answered and people might still find this answer.
The important part of your question is:
One more caveat. If I start this Express.js service and don't send any requests then SIGINT terminates properly. Clearly there is something fundamental that I'm missing here?`
What you are missing is that by default express keeps connections open (HTTP keep-alive) for re-use. So, when there has been a (recent) request there's still something on the event-loop and that's the reason your app is not closing.
Using process.exit()
will work, but is like sending another ^C, and may hide the fact that there is still something else open (e.g. database connections). Your app should just close when there's nothing left on the event-loop.
So, I modified your example, setting a 5 second keep-alive on the connection so it will graceful shutdown in a reasonable time.
var express = require('express');
var serverPort = 3000;
var app = express();
var server = app.listen(serverPort);
// HTTP Keep-Alive to a short time to allow graceful shutdown
server.on('connection', function (socket) {
socket.setTimeout(5 * 1000);
});
// Handle ^C
process.on('SIGINT', shutdown);
// Do graceful shutdown
function shutdown() {
console.log('graceful shutdown express');
server.close(function () {
console.log('closed express');
});
}
console.log('running server: http://localhost:' + serverPort);
Upvotes: 20