Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly handle SIGINT with Express.js?

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?

like image 651
Jacob Marble Avatar asked Jan 17 '13 04:01

Jacob Marble


People also ask

Does Express use gzip?

Here compression means the gzip compression on the express server. You can use the compression middleware to add easy gzip compression to your server.

What is Sigint in NodeJS?

The SIGINT signal is sent to a process by its controlling terminal when a user wishes to interrupt the process. This is typically initiated by pressing Ctrl+C . The SIGTERM signal is sent to a process to request its termination. Unlike the SIGKILL signal, it can be caught and interpreted or ignored by the process.

Why is Express JS Unopinionated?

Express JS is minimal and unopinionated​Express uses less overhead in the core framework so that makes it minimal and a good choice for building out large web applications. You don't want to have a framework that fills your codebase with lots of bloatware that you are never gonna use.

Should I use Fastify or Express?

Fastify provides full encapsulation for plug-ins, automatically parses JSON with relatively faster rendering, and provides quick routing. Among other benefits, Fastify also has a cleaner syntax for writing async code in controllers. Express, however, has a stronger user base with plenty of documentation available.


3 Answers

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.

like image 129
nneonneo Avatar answered Oct 27 '22 21:10

nneonneo


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);
like image 15
Whyhankee Avatar answered Oct 27 '22 21:10

Whyhankee


I am using this code:

server.close(() => {
  process.exit(0)
})
like image 8
Kirill Husiatyn Avatar answered Oct 27 '22 23:10

Kirill Husiatyn