Search code examples
javascriptnode.jsexpressnodejs-server

close server from within router


I create an express app like this

const express = require('express')
const app = express();

app.use(express.static(path.join(__dirname, 'public')));

app.post('/close', async (_, res) => {
  res.status(200);
  res.end();
  app.close();
});

module.exports = app;

I instantiate it in another module

const myApp = require('./app.js');
myApp.listen(port, () => {
  console.log(`Started server on ${port}`);
});

I want the server to shut itself down when it receives a post request to /close. At the moment, I just get a app.close is not a function error.

I know I can close a server externally like this

const server = myApp.listen(port, () => {
  console.log(`Started server on ${port}`);
});
server.close();

but I want to close the server on a post request to /close, how can I do that?


Solution

  • To get access to your server object, try using

    req.connection.server
    

    from within your route handler.

    .close() makes the server stop listening for new connections. Already-established connections are not affected. The server object emits a 'close' event when all open connections have disconnected.

    process.exit() stops your whole nodejs app.

    So, this code might do what you want.

    app.post('/close', (req, res, next) => {
      res.status(200)
      res.end()
      const server = req.connection.server
      if (server.listening) {
        server.addEventListener('close', ev => {
          console.log('server closed. See ya later alligator.')
          process.exit(0)
        })
        console.log('closing server')
        server.close()
      }
    });
    

    If you need to get the server object from your app object (if getting it from your req object isn't good enough), you could put in a little middleware function like this.

    app.use( function adornApp( req, res, next ) {
      req.app.locals.server = req.connection.server
      next()
    } )
    

    Then you'll be able to get your server from app.locals.server once your middleware is first invoked.