Sling Academy
Home/Node.js/How to programmatically exit a Node.js program

How to programmatically exit a Node.js program

Last updated: December 30, 2023

Introduction

Node.js applications run on a single-threaded event loop, which manages asynchronous operations and allows for high throughput. However, there are scenarios where you might want to programmatically terminate a Node.js program. This could be due to an error, completion of the required task, or response to specific user input. In this guide, we’ll delve into different methods to gracefully or forcefully exit a Node.js program, while using the latest syntax such as arrow functions, async/await, and ES modules.

Basic Method: process.exit()

The process global object in Node.js provides process.exit() method that is used to terminate the Node.js process. You can call it with an optional exit code:

process.exit(0); // Exits with a 'success' code 
process.exit(1); // Exits with a 'failure' code

Calling process.exit() will force the process to stop quickly, potentially cutting off asynchronous operations and event handling in progress. Typically, an exit code of 0 signifies successful execution, while a non-zero exit code signifies an error or abnormal termination.

Cleanup before Exiting

Sometimes, you might want to perform certain cleanup tasks before the program exits. Node.js provides the 'exit' event, which can be used to run some cleanup code:

process.on('exit', (code) => {
    console.log('Process is exiting with code:', code);
});
process.exit(0);

However, the 'exit' event should only be used to perform synchronous operations because the event loop is no longer being polled at this point: no asynchronous task will be executed.

Using Signals to Exit

You can also use signals to intercept and handle termination requests for a process. For example, listening for SIGTERM and SIGINT:

process.on('SIGTERM', () => {
  console.log('Received SIGTERM, shutting down.');
  process.exit(0);
});

process.on('SIGINT', () => {
  console.log('Received SIGINT, shutting down.');
  process.exit(0);
});

SIGTERM is conventionally used to request a graceful shutdown, whereas SIGINT is generated by pressing Ctrl + C in the terminal. By default, both signals exit the process, but by capturing them, you can perform cleanup before exiting.

Exiting Asynchronously

To run asynchronous operations before exiting, we cannot rely on the 'exit' event. Instead, we should perform asynchronous cleanup in response to a signal or an error and then call process.exit():

const performCleanup = async () => {
    // Replace with actual async cleanup logic
    await new Promise(resolve => setTimeout(resolve, 1000));
    console.log('Cleanup completed.');
    process.exit(0);
};

process.on('SIGINT', async () => {
  console.log('Received SIGINT. Cleaning up...');
  await performCleanup();
});

Note that we must invoke process.exit() after performCleanup() to ensure the event loop doesn’t continue running additional events or operations after the cleanup has completed.

Graceful Shutdown in Servers

If your Node.js application is running an HTTP server, it’s important to achieve a graceful shutdown by allowing ongoing requests to complete and refusing new ones. Here is how you can gracefully shutdown an HTTP server:

import http from 'http';

const server = http.createServer((req, res) => {
    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/plain');
    res.end('Hello World\n');
});

server.listen(3000, () => {
  console.log('Server running...');
});

const gracefulShutdown = () => {
  server.close(() => {
    console.log('Server is closing...');
    process.exit(0);
  });
  setTimeout(() => {
    console.error('Forcing shutdown...');
    process.exit(1);
  }, 5000); // Force shutdown after 5 seconds
};

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

In the above code, server.close() stops the server from accepting new connections; meanwhile, existing connections are allowed to complete. After calling this method, if the server does not shut down within the specified time frame, a forced shutdown is initiated to prevent the server from hanging indefinitely.

Conclusion

There are various ways to exit a Node.js program, ranging from the abrupt process.exit() method to a more refined strategy involving signals for a graceful shutdown. When exiting your applications, remember to clean up any resources and maintain the stability of your service. Knowing the right tools and using them judiciously minimizes potential disruption or data loss.

By considering the appropriateness of immediate versus graceful exits, acknowledging the need for asynchronous cleanup, and understanding the requirements of running services, you can create robust Node.js applications that gracefully handle shutdown scenarios across different deployments.

Next Article: Node.js & TypeScript: How to Set Up CI/CD with GitHub Actions

Previous Article: How to Schedule Tasks in Node.js

Series: Node.js Intermediate Tutorials

Node.js

You May Also Like

  • NestJS: How to create cursor-based pagination (2 examples)
  • Cursor-Based Pagination in SequelizeJS: Practical Examples
  • MongooseJS: Cursor-Based Pagination Examples
  • Node.js: How to get location from IP address (3 approaches)
  • SequelizeJS: How to reset auto-increment ID after deleting records
  • SequelizeJS: Grouping Results by Multiple Columns
  • NestJS: Using Faker.js to populate database (for testing)
  • NodeJS: Search and download images by keyword from Unsplash API
  • NestJS: Generate N random users using Faker.js
  • Sequelize Upsert: How to insert or update a record in one query
  • NodeJS: Declaring types when using dotenv with TypeScript
  • Using ExpressJS and Multer with TypeScript
  • NodeJS: Link to static assets (JS, CSS) in Pug templates
  • NodeJS: How to use mixins in Pug templates
  • NodeJS: Displaying images and links in Pug templates
  • ExpressJS + Pug: How to use loops to render array data
  • ExpressJS: Using MORGAN to Log HTTP Requests
  • NodeJS: Using express-fileupload to simply upload files
  • ExpressJS: How to render JSON in Pug templates