question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Using with express app

See original GitHub issue

This is the express, how can I wrap it around stoppable?

const app = require('./src/app');

const port = process.env.PORT || 3000;
app.listen(port, () => {
  console.log(`Listening on port ${port}...`);
});

Issue Analytics

  • State:open
  • Created 3 years ago
  • Comments:5

github_iconTop GitHub Comments

2reactions
mstaicucommented, Mar 8, 2021

Not at all. Nice! Didn’t know that @maxbarbul, TIL. As for my solution, I decided to temporarily go with the following approach of keeping track of connections and manually handling the node process termination

import type { Socket } from 'net';

import app from './app';

const server = app.listen(process.env.PORT, () => {
  console.log(`Running on port ${process.env.PORT}`);
});

const sockets = new Set<Socket>();

server.on('connection', socket => {
  sockets.add(socket);
  server.once('close', () => {
    sockets.delete(socket);
  });
});

/**
 * need this in docker container to properly exit since node doesn't handle SIGINT/SIGTERM
 * this also won't work on using npm start since:
 *
 * https://github.com/npm/npm/issues/4603
 * https://github.com/npm/npm/pull/10868
 * https://github.com/RisingStack/kubernetes-graceful-shutdown-example/blob/master/src/index.js
 */

// Quit on CTRL - C when running Docker in Terminal
process.on('SIGINT', () => {
  console.info('Received SIGINT, gracefully shutting down');
  shutdown();
});

// Quit on docker stop command
process.on('SIGTERM', () => {
  console.info('Received SIGTERM, gracefully shutting down');
  shutdown();
});

const shutdown = () => {
  /**
   * The server is finally closed when all connections are ended and the server emits a 'close' event.
   * waitForSocketsToClose will give existing connections 10 seconds to terminate before destroying the sockets
   */
  waitForSocketsToClose(10);

  /**
   * https://nodejs.org/api/net.html#net_server_close_callback
   *
   * server.close([callback])
   *
   * callback <Function> Called when the server is closed.
   * Returns: <net.Server>
   *
   * Stops the server from accepting new connections and keeps existing connections
   * This function is asynchronous, the server is finally closed when all connections are ended and the server emits a 'close' event.
   * The optional callback will be called once the 'close' event occurs. Unlike that event, it will be called with an Error as its only argument if the server was not open when it was closed.
   */

  server.close(err => {
    if (err) {
      console.error(err);
      process.exitCode = 1;
    }

    process.exit();
  });
};

const waitForSocketsToClose = (counter: number) => {
  if (counter > 0) {
    console.log(
      `Waiting ${counter} more ${
        counter !== 1 ? 'seconds' : 'second'
      } for all connections to close...`,
    );

    return setTimeout(waitForSocketsToClose, 1000, counter - 1);
  }

  console.log('Forcing all connections to close now');

  for (const socket of sockets) {
    socket.destroy();
    sockets.delete(socket);
  }
};

export { server };
2reactions
mstaicucommented, Dec 23, 2020

Try the following: (I’ve thrown in terminus for health checking and graceful shutdown)

import { createTerminus } from '@godaddy/terminus';
import stoppable from 'stoppable';

import app from './src/app';

const server = stoppable(
  app.listen(process.env.PORT, () => {
    console.log(`Express API running on port ${process.env.PORT}`);
  }),
);

const onSignal = () => {
  console.log('Received SIGTERM, closing down...');

  return new Promise((resolve, reject) => {
    server.stop(err => {
      if (err) {
        reject(err);
      }
      resolve(0);
    });
  });
};

const onHealthCheck = () => Promise.resolve();

createTerminus(server, {
  healthChecks: {
    '/healthz': onHealthCheck,
  },
  signals: ['SIGINT', 'SIGTERM'],
  onSignal,
});
Read more comments on GitHub >

github_iconTop Results From Across the Web

Express.js | app.use() Function - GeeksforGeeks
The app.use() function is used to mount the specified middleware function(s) at the path which is being specified. It is mostly used to...
Read more >
Hello world example - Express.js
First create a directory named myapp , change to it and run npm init . Then install express as a dependency, as per...
Read more >
node.js - NodeJS / Express: what is "app.use"? - Stack Overflow
app.use is a way to register middleware or chain of middlewares (or multiple middlewares) before executing any end route logic or intermediary route...
Read more >
Express.js – app.use() Method - Tutorialspoint
The app.use() method mounts or puts the specified middleware functions at the specified path. This middleware function will be executed only ...
Read more >
The `app.use()` Function in Express - Mastering JS
In Express, everything is middleware. Internally, an Express app has a middleware stack, and calling use() adds a new layer to the stack....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found