9

I'm trying to properly close a MongoDB connection when the app is shut down. Here is the code:

var express = require('express')
  , http = require('http')
  , mongoose = require('mongoose')
  , path = require('path');

var app = express();

app.set('port', process.env.PORT || 3000);

mongoose.connect('mongodb://localhost/test');

// some post and get handlers etc. (removed for shorter output)

var server = app.listen(app.get('port'), function(){
    console.log('Express server listening on port ' + app.get('port'));
});

function cleanup () {
    server.close(function () {
        console.log("Closed out remaining connections.");
        mongoose.connection.close();
        process.exit();
    });

    setTimeout( function () {
        console.error("Could not close connections in time, forcing shut down");
        process.exit(1);
    }, 30*1000);
}

process.on('SIGINT', cleanup);
process.on('SIGTERM', cleanup);

All is well and works when the app starts for the first time. When I hit Ctrl-c right after it has started, it cleanly shuts down with the Closed out remaining connections. message. However, as soon as the app interacts with the database or even serves a static page, and I try to shut it down after that, it exits with the following error:

net.js:1225
    throw new Error('Not running');
          ^
Error: Not running
    at Server.close (net.js:1225:11)
    at process.cleanup (<...>/app.js:77:12)
    at process.EventEmitter.emit (events.js:92:17)
    at Signal.wrap.onsignal (node.js:756:46)
22 Aug 15:15:28 - [nodemon] exiting

Any ideas what is causing this error and how I could fix it?

mart1n
  • 5,135
  • 5
  • 35
  • 72
  • after you serve a static page, does it take two ctrl-c presses to see this error compared to one time when no serving is done. – Chandu Aug 22 '13 at 14:52
  • Nope, just one `Ctrl-c`. – mart1n Aug 22 '13 at 14:57
  • The reason the server is not closing is because there are remaining sockets that are open. You must keep track of them and close them one by one. To understand the process better and to lear how to manage sockets, read https://dev.to/gajus/how-to-terminate-a-http-server-in-node-js-ofk. – Gajus Jan 20 '20 at 09:19

3 Answers3

4

When server.close is called, there are two properties that are checked.

   handle<tcp handle>
   connections

Responsible code fragment of server.close responsible for this error;

  if (!this._handle) {
    // Throw error. Follows net_legacy behaviour.
    throw new Error('Not running');
  }

Only if handle===null and connections ===0 that the callback passed to close is called.

Case : Server is started and sent the signal with no serving.

Before close is called;

  handle === TCP handle.
  connection===0;

After close handle===null; connection===0;

The callback gets called.

Case : Server is started and sent the signal after a request server.

Before close is called;

  handle === TCP.handle;
  connection===1;

After close handle === null; connection===1;

No callback is fired.

Second time when you press ctrl-c

Before close is called;

  handle === null;
  connection===1;

since handle===null , the check throws the error you are seeing.

Chandu
  • 4,371
  • 2
  • 15
  • 12
  • So how do I make sure all connections are properly closed? I thought closing the DB connection was all that was required? – mart1n Aug 22 '13 at 15:10
  • one easy way to do it, In cleanup function , place the following statement before server.close(fn) server.connections=0; – Chandu Aug 22 '13 at 16:33
  • Thanks, that seems to work. But, it seems that `server.connections` has been deprecated. The following message is returned when I shut down the app: `connections property is deprecated. Use getConnections() method`. Any idea how to use this method to achieve the same thing as you specified above? – mart1n Aug 23 '13 at 08:33
  • try server._connections=0 – Chandu Aug 23 '13 at 10:17
2

The reason your server has open connections is because you are sending Connection: keep-alive header.

Morgan's answer closes all the connections on the server cleanly, disconnecting all of the clients.

If you are just testing your application and want to shut it down cleanly before/after tests I recommend sending Connection: close header and server.close() will work as expected.

Mihai Tomescu
  • 1,315
  • 14
  • 19
1

I don't think setting server._connections = 0 actually closes the connection. It just satisfies the conditions to get your callback executed.

You might want to try something like this:

// Everything else how you had it before ...

var sockets = [];

server.on('connection', function(socket) {
  sockets.push(socket);
});

function cleanup () {
  server.close(function () {
    console.log("Closed out remaining connections.");
     // mongoose.connection.close(); Might want to comment this out
    process.exit();
  });

  // Add this part to manually destroy all the connections.
  sockets.forEach(function(socket) {
    socket.destroy();
  });

  // setTimeout() ...
}
Morgan
  • 617
  • 5
  • 11
  • 3
    **Warning**: This is a memory leak waiting to happen. The `sockets` array grows without bounds. – Darkhogg Sep 27 '15 at 12:11
  • This is true. It would perhaps be better to use an http.Agent and https://nodejs.org/api/http.html#http_agent_destroy – Morgan Sep 28 '15 at 16:17