npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

exit-hook-plus

v0.2.0

Published

Do something before the program exits or when the program crashes!

Readme

exit-hook-plus

Do something and then automatically exit the program when these cases happen:

  • an unhandledRejection or uncaughtException event occurred
  • received a SIGHUP, SIGINT, SIGTERM or SIGBREAK signal

Or do something before the program exits due to:

  • No more operations are pending (normal exit)
  • a process.exit call (synchronous hooks only, read the text below)

Install

The library comes with .d.ts, so you are free from installing something like @types/exit-hook-plus.

$ npm install exit-hook-plus

Usage

APIs

// Remove the default exit logger for exit reasons with category 'exception' and 'signal'.
//
// For category 'exception' reasons, the logger will print 'the program is now exiting due to unhandled exception: (reason.errorOrReason or its stack when it's an error)'.
// For category 'signal' reasons, the logger will print 'the program is now exiting due to receiving signal: (signal name)'.
function disableDefaultExitLogger() {}

// Add an exit hook function.
//
// The function can be either sync or async.
//
// When using async hooks, you should be aware that they will NOT be executed if you manually
// call process.exit to termintate the program, see the "Warnings" below.
function addExitHook(hook: ExitHook) {}

// Remove an existing hook function.
// It will do nothing if the given hook does not exist.
function removeExitHook(hook: ExitHook) {}

// Pass the 'extra' object to all the hooks and automatically call process.exit with 'exitCode'.
//
// Notice that by this way you are free from the async hook issue above.
// It is a sync function but under the hood it asynchronously executes the hooks and terminate the program
// so you should treat it as the last action in your program and DO NOT run other codes after calling it.
//
// If you call it without any arguments, the exitCode will default to 0 and extra to undefined.
function executeAllHooksAndTerminate(exitCode: number = 0, extra?: any) {}

Examples

A unhandledRejection or uncaughtException event

In this case, exit-hook-plus will automatically terminate the program with exit code 1 after executing all the exit hook functions.

const { addExitHook } = require('exit-hook-plus');

// the hook can be either async or sync
// it will be executed after the Promise.reject is called
addExitHook(async (reason) => {
  // reason.category === 'exception'
  // reason.errorOrReason is the argument of Promise.reject() in this case
  // so reason.errorOrReason.message === 'test error'
  console.dir(reason);
});

(function () {
  // trigger an unhandledRejection event
  return Promise.reject(new Error('test error'));
})();

A SIGHUP, SIGINT, SIGTERM or SIGBREAK signal

In this case, exit-hook-plus will terminate the program with following exit code after executing all the exit hook functions:

  • SIGUP: 128+1 = 129
  • SIGINT: 128+2 = 130
  • SIGTERM: 128+15 = 143
  • SIGBREAK: 128+21 = 149
const { addExitHook } = require('exit-hook-plus');

// the hook can be either async or sync
// it will be executed after a SIGHUP, SIGINT, SIGTERM or SIGBREAK signal was sent
// you can try it manually by pressing Ctrl+C to emit an SIGINT signal
addExitHook(async (reason) => {
  // reason.category === 'signal'
  // reason.signal === 'SIGINT'
  console.dir(reason);
});

// wait for signals
setTimeout(() => {}, 100000);

A normal exit or a process.exit call

const { addExitHook } = require('exit-hook-plus');

// when you use process.exit to end the process
// no async hooks can be used!
addExitHook((reason) => {
  // reason.category === 'trivial'
  // reason.exitCode === 88
  console.dir(reason);
});

process.exit(88);

A real world example

const { addExitHook, executeAllHooksAndTerminate } = require('exit-hook-plus');

// we initialize connections to kafka and mongodb
// and add the exit hook for disconnect functions
// it's a bit like the 'defer' keyword in golang :D
console.info('connecting to kafka');
await kafkaDataConsumer.connect();
for (const topic of TARGET_TOPICS) {
  await kafkaDataConsumer.subscribe({ topic });
}
addExitHook(async () => await kafkaDataConsumer.disconnect());

console.info('connecting to mongodb');
await mongo.connect();
addExitHook(async () => await mongo.close());

if (liveStreamEnded) {
  console.info('live stream ended, program will exit soon');
  // now terminate the program
  // here we should NOT use process.exit because it will make async hooks unable to execute, see the "Warnings" below
  executeAllHooksAndTerminate();
}

Warnings

Hooks and try-catch

All the hooks specified by addExitHook(...) will each run with try-catch folded under the hood and remains quiet even if it runs into error. As a result, you should prepare your own try-catch block in the hook function if needed.

Asynchronous hooks and process.exit()

If the program is called to exit using process.exit(), only the synchronous hooks will be executed rather than the asynchronous ones because during the process the event loop is no longer available. For details, check out https://nodejs.org/api/process.html#process_event_exit.

Windows and process.kill(signal)

According to Tappi/async-exit-hook. On windows process.kill(signal) immediately kills the process, and does not fire signal events, and as such, cannot be used to gracefully exit.

Hook unhandledRejection and uncaughtException events properly

The correct use of hooking them is mainly to perform cleanup of allocated resources (e.g. file descriptors, connections, etc) before shutting down the process. It is not safe to resume normal operation after these events happened. For details, please refer to https://nodejs.org/api/process.html#process_warning_using_uncaughtexception_correctly.

Compatibility

The library is written in TypeScript 4.1.3 and Node v14, but is compiled into ES5 and tested in Node v10, v12 and v14 environment.

Reference

  • https://github.com/Tapppi/async-exit-hook
  • https://nodejs.org/api/process.html
  • https://blog.heroku.com/best-practices-nodejs-errors