1

I want my Node program to perform some tasks (eg. closing down the database connection and deleting some objects) before exiting, even when the program is stopped manually (via Ctrl+C or the kill command for example). Is this possible?

I've tried using process.on('exit') and process.on('SIGINT'), but my tasks never finish before the program exits and I'm not sure whether this handles the kill command too:

require('dotenv').config()
const log = require('./middleware/log')
const error = require('./middleware/error')
const mongoose = require('mongoose')
const puppeteer = require('puppeteer')
const cleanup = require('./middleware/cleanup');

(async () => {

  // handle Ctrl+C
  process.on('SIGINT', () => {
    cleanup(browser) // this never finishes before the program ends
    process.exit(2)
  })

  // log program exit
  process.on('exit', (code) => {
    if (code === 2) {
      log('Program exited manually.')
    } else if (code === 1) {
      log('Program crashed.')
    } else {
      log('Program exited.')
    }
    cleanup(browser) // I've tried putting it here too, but it still doesn't finish before the program ends
    process.exit(code)
  })

  await mongoose.connect(
    'mongodb://app:' + process.env.MONGO_PW_DEV + '@' + process.env.MONGO_IP_DEV + ':' + process.env.MONGO_PORT_DEV + '/' + process.env.MONGO_DB_DEV,
    {
      useNewUrlParser: true
    }
  )

  const browser = await puppeteer.launch({ headless: true })
  page = await browser.newPage()

  // do stuff

  cleanup(browser)

})().catch(async (err) => {
  cleanup(browser)
  error(err)
})

Here is my cleanup function:

const mongoose = require('mongoose')

module.exports = (browser) => {
  mongoose.disconnect()
    .then(res => {
      browser.close()
        .then(res => {
          return
        })
    })
}
bumbleshoot
  • 1,082
  • 2
  • 17
  • 32
  • 1
    Possible duplicate of [doing a cleanup action just before node.js exits](https://stackoverflow.com/questions/14031763/doing-a-cleanup-action-just-before-node-js-exits) – Thamaraiselvam Feb 22 '19 at 11:10
  • paste your sample program, this will make more clear what you are trying to do – Sohan Feb 22 '19 at 11:12
  • 1
    @Sohan OP is asking about how to gracefully end when the program is killed (or if it is at least possible). This is not about debugging. – Seblor Feb 22 '19 at 11:15
  • @Thamaraiselvam I have tried that but the program always ends before the tasks in `process.on('exit')` can finish. – bumbleshoot Feb 22 '19 at 11:20
  • What are the possible way you have tried please highlight those. – Sohan Feb 22 '19 at 11:21
  • @Sohan I edited my question to include what I've tried. Thanks – bumbleshoot Feb 22 '19 at 11:29

3 Answers3

3

In the case of Graceful shutdown in NodeJS, handling using kill signal

A signal is an asynchronous notification sent to a process or to a specific thread to notify an event that occurred.

See more about Node.js Signal Events

When the NodeJS process receives a signal, signal events will be emitted e.g. 'SIGINT', 'SIGTERM', etc.

  • 'SIGINT' generated with +C in the terminal.
  • The 'SIGTERM' signal is a generic signal used to cause program termination. Unlike 'SIGKILL', this signal can be blocked, handled, and ignored. It is the normal way to politely ask a program to terminate.
  • The shell command kill generates 'SIGTERM' by default.

More about Termination Signals

We just need to add handler to receive 'SIGTERM' signal:

process.on('SIGTERM', () => {
  console.log('Signal received.');
});

In your case, I think process events might help

Moreover for the normal case, for listening to the exit event and set the program to perform other tasks, process can emit events such as beforeExit or exit

See 'process' events

Event: 'exit' The 'exit' event is emitted when the Node.js process is about to exit as a result of either:

  • The process.exit() method being called explicitly;
  • The Node.js event loop no longer having any additional work to perform.

There is no way to prevent the exiting of the event loop at this point, and once all 'exit' listeners have finished running the Node.js process will terminate.

Hope it help! :)

More about Graceful shutdown in NodeJS

  • Thanks, this is very helpful! I didn't know that SIGTERM would be emitted by the `kill` command. My problem though, is that even if I use these event listeners, the tasks are never able to finish before the program ends. Please see the code I added above. – bumbleshoot Feb 22 '19 at 11:33
0

As you have not shared the code but you can try something like this,

      process.on('SIGTERM', () => {
      console.info('SIGTERM signal received.');
      console.log('Closing http server.');
      expressServer.close(() => {
        console.log('Http server closed.');
        // boolean means [force], see in mongoose doc
        mongoose.connection.close(false, () => {
          console.log('MongoDb connection closed.');
          process.exit(0);
        });
      });
   });
Sohan
  • 6,252
  • 5
  • 35
  • 56
  • Thank you, I have edited my code above to show what I tried and it's pretty much what you have here. My problem is that the program always exits before the tasks (closing Express, Mongoose, etc.) finish. – bumbleshoot Feb 22 '19 at 11:31
0

To catch Ctrl+C, ensure you've added process.stdin.resume():

process.stdin.resume();
process.on('SIGINT', function() {
  console.log('Interrupted');
  process.exit();
});

*from https://stackoverflow.com/a/49458139/2154075

IvanM
  • 2,913
  • 2
  • 30
  • 30