Search code examples
node.jshttphttpshttpserver

how to stop accepting new requests before closing existing ones?


This runs without error:

const app = express();

const server = app.listen(3900, '0.0.0.0', () => {
  console.log('listening...');
});

process.once('SIGINT', () => {

  console.log('got SIGINT.')

  setTimeout(() => {
    console.log('ending process due to SIGINT + subsequent Timeout.')
    process.exit(0);
  }, 3000);

  server.closeIdleConnections();  // <<<
  server.closeAllConnections();  // <<<<

  server.close(err => {
    if (err) {
      console.error(err);
    }
    console.log('closed server, and now shutting down due to SIGINT.')
    process.exit(0);
  });
});

but my question is - is this the best way to stop accepting new connections before ending the existing connections/requests?

how are "idle" connections defined?


Solution

  • is this the best way to stop accepting new connections before ending the existing connections/requests?

    I guess "best" is subjective and it depends on the application. However, calling the synchronous server.closeAllConnections() before allowing the asynchronous server.close() to finish it's work is not the most graceful way to stop any ongoing connections (those currently sending a request or waiting for a response). In short, I would say no this is not the most graceful way to stop accepting new connections before ending existing connections due to the abrupt nature of closeAllConnections.

    how are "idle" connections defined?

    I'll link you to the documentation which states that idle connections are connections connected to this server which are not sending a request or waiting for a response.

    To make your SIGINT handler more graceful, I would recommend a slight modification by removing the call to server.closeAllConnections() and nesting your setTimeout inside of the close callback. Something along these lines:

    process.once('SIGINT', () => {
      /**
       * Immediately close any idle connections.
       * May not be strictly necessary since as of Node v19.0.0
       * server.close() will also close idle connections before
       * returning / firing the 'close' event.
       * 
       * Either way, it may reduce the workload of server.close()
       * by minimizing the connections it must close or wait to
       * finish to those that were already active, or only created
       * in the short time span between calling closeIdleConnections()
       * and close().
       */
      server.closeIdleConnections()
    
      // Now stop the server from accepting new connections while keeping existing connections.
      server.close((err) => {
        // Force close all connections after a specified timeout
        setTimeout(() => {
          server.closeAllConnections()
          process.exit(0)
        }, 3000).unref() // prevents the event loop from remaining active so your server can shutdown earlier if this timeout is not needed.
      })
    })
    

    Note, that the callback to server.close will only receive an error if you are attempting to shutdown a server that was not running. This is noted in the documentation for net.Server.close().