GithubHelp home page GithubHelp logo

exit-hook's Introduction

exit-hook

Run some code when the process exits

The process.on('exit') event doesn't catch all the ways a process can exit.

This package is useful for cleaning up before exiting.

Install

npm install exit-hook

Usage

import exitHook from 'exit-hook';

exitHook(signal => {
	console.log(`Exiting with signal: ${signal}`);
});

// You can add multiple hooks, even across files
exitHook(() => {
	console.log('Exiting 2');
});

throw new Error('๐Ÿฆ„');

//=> 'Exiting'
//=> 'Exiting 2'

Removing an exit hook:

import exitHook from 'exit-hook';

const unsubscribe = exitHook(() => {});

unsubscribe();

API

exitHook(onExit)

Register a function to run during process.exit.

Returns a function that removes the hook when called.

onExit

Type: (signal: number) => void

The callback function to execute when the process exits.

asyncExitHook(onExit, options)

Register a function to run during gracefulExit.

Returns a function that removes the hook when called.

Please see Async Notes for considerations when using the asynchronous API.

onExit

Type: (signal: number) => (void | Promise<void>)

The callback function to execute when the process exits via gracefulExit, and will be wrapped in Promise.resolve.

options

Type: object

wait

Type: number

The amount of time in milliseconds that the onExit function is expected to take. When multiple async handlers are registered, the longest wait time will be used.

import {asyncExitHook} from 'exit-hook';

asyncExitHook(async () => {
	console.log('Exiting');
}, {
	wait: 300
});

throw new Error('๐Ÿฆ„');

//=> 'Exiting'

Removing an asynchronous exit hook:

import {asyncExitHook} from 'exit-hook';

const unsubscribe = asyncExitHook(async () => {
	console.log('Exiting');
}, {
	wait: 300
});

unsubscribe();

gracefulExit(signal?: number): void

Exit the process and make a best-effort to complete all asynchronous hooks.

If you are using asyncExitHook, consider using gracefulExit() instead of process.exit() to ensure all asynchronous tasks are given an opportunity to run.

import {gracefulExit} from 'exit-hook';

gracefulExit();

signal

Type: number
Default: 0

The exit code to use. Same as the argument to process.exit().

Asynchronous Exit Notes

tl;dr If you have 100% control over how your process terminates, then you can swap exitHook and process.exit for asyncExitHook and gracefulExit respectively. Otherwise, keep reading to understand important tradeoffs if you're using asyncExitHook.

Node.js does not offer an asynchronous shutdown API by default #1 #2, so asyncExitHook and gracefulExit will make a "best effort" attempt to shut down the process and run your asynchronous tasks.

If you have asynchronous hooks registered and your Node.js process is terminated in a synchronous manner, a SYNCHRONOUS TERMINATION NOTICE error will be logged to the console. To avoid this, ensure you're only exiting via gracefulExit or that an upstream process manager is sending a SIGINT or SIGTERM signal to Node.js.

Asynchronous hooks should make a "best effort" to perform their tasks within the wait time, but also be written to assume they may not complete their tasks before termination.

exit-hook's People

Contributors

bendingbender avatar dflupu avatar jakobo avatar julusian avatar richienb avatar rpnzl avatar scg82 avatar sindresorhus avatar tapppi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

exit-hook's Issues

Feature request: Ability to use custom logger

We would like to write all debug messages from exit-hook to our own Kibana with some area field predefined.

Currently, exit-hook uses console.log to write any logs.

Could you please introduce ability to intercept log messages or override the logger at all?

v3.1.0: exit-hook causes scripts to exit with error code 128 instead of 0

Hi, thanks for creating exit-hook! It is extremely useful. ๐Ÿ™‚

I'm reporting an apparent regression in v3.1.0. Here is a minimal repro.

To reproduce, run:

git clone https://gist.github.com/201fd03a6f44827153b8ded608ff5f5b.git repro
cd repro
npm i
node index.js
echo $?

With exit-hook v3.1.0, this will print 128 (the error code). Whereas if you do:

npm i --save [email protected]
node index.js
echo $?

Then it will print 0 (the successful exit code).

The index.js file itself is quite minimal:

#!/usr/bin/env node

import exitHook from 'exit-hook'

exitHook(() => {
})

Here is the relevant environment info:

$ node --version
v16.18.0
$ npm --version
8.19.2
$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=22.04
DISTRIB_CODENAME=jammy
DISTRIB_DESCRIPTION="Ubuntu 22.04.1 LTS"

Thanks in advance for taking a look!

pm2 stop do not trigger the hook

run nodejs app as:
pm2 start app.js
it run successfully. Then I tried to stop app:
pm2 stop id

But it can not trigger exitHook()

Node stdout/stderr buffer flushing is still a problem. Wait for console.log to complete before exit

Hello! Thanks for your awesome projects. They provide really good workarounds for current JS ecosystem strange problems.

I've faced an issue with flushing the stdout/stderr buffers before the exit.
Seems to be that is the root problem.

Some hacks like in https://github.com/cowboy/node-exit/blob/master/lib/exit.js is still required in modern node (v20.4.0).

My proposal is to integrate the exit.js solution in exit-hook, as it's not possible to use these modules together.

gracefulExit() always prints SYNCHRONOUS TERMINATION NOTICE

For me, the library always prints the synchronous termination notice:

$ node exit-test.js                                                     
foo
bar
quux
SYNCHRONOUS TERMINATION NOTICE: When explicitly exiting the process via process.exit or via a parent process, asynchronous tasks in your exitHooks will not run. Either remove these tasks, use gracefulExit() instead of process.exit(), or ensure your parent process sends a SIGINT to the process running this code.

For testing purposes, the code I'm running is the same as the unit test (https://github.com/sindresorhus/exit-hook/blob/main/fixture-async.js), but './index.js' replaced with exit-code:

import exitHook, { asyncExitHook, gracefulExit } from 'exit-hook'

exitHook(() => {
  console.log('foo')
})

exitHook(() => {
  console.log('bar')
})

const unsubscribe = exitHook(() => {
  console.log('baz')
})

unsubscribe()

asyncExitHook(
  async () => {
    await new Promise((resolve) => {
      setTimeout(() => {
        resolve()
      }, 100)
    })

    console.log('quux')
  },
  {
    minimumWait: 200,
  }
)

gracefulExit()

Running on my Mac:

$ npx envinfo --system --binaries --npmPackages "exit-hook"           

  System:
    OS: macOS 12.6
    CPU: x64 Intel(R) Core(TM) i7-7567U CPU @ 3.50GHz
    Memory: 17.28 MB / 16.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 18.10.0 - ~/.nvm/versions/node/v18.10.0/bin/node
    npm: 8.19.2 - ~/.nvm/versions/node/v18.10.0/bin/npm
  npmPackages:
    exit-hook: ^3.1.0 => 3.1.0 

and in the node:18 container image:

  System:
    OS: Linux 5.10 Debian GNU/Linux 11 (bullseye) 11 (bullseye)
    CPU: (2) x64 Intel(R) Core(TM) i7-7567U CPU @ 3.50GHz
    Memory: 898.09 MB / 1.94 GB
    Container: Yes
    Shell: 5.1.4 - /bin/bash
  Binaries:
    Node: 18.10.0 - /usr/local/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 8.19.2 - /usr/local/bin/npm
  npmPackages:
    exit-hook: ^3.1.0 => 3.1.0

cc @jakobo

Incorrect docs

Docs should be updated to reflect the latest changes. Namely, the async options name change from wait -> minimumWait.

Make `gracefulExit` return `never` instead of `void`

Hello ๐Ÿ‘‹,

Shouldn't gracefulExit reflect the return type of process.exit? (defined here).

With this change, it will correctly tell TypeScript that everything called after gracefulExit won't be executed and don't add the void type where it shouldn't be.

Here is a playground showing the issue: https://tsplay.dev/wgo5bw
The same playground using never: https://tsplay.dev/WY5jEW

As a workaround, I'm using module augmentation to redefine gracefulExit definition:

// global.d.ts

module "exit-hook" {
  export function gracefulExit(signal?: number): never;
}

Allow async code

Currently, only sync code can be executed.

Could use the beforeExit event.

Cannot use require on the module

I get the following error:
Error [ERR_REQUIRE_ESM]: require() of ES Module C:\Users\user\Desktop\folder\node_modules\exit-hook\index.js from C:\Users\user\Desktop\folder
Instead change the require of index.js in C:\Users\user\Desktop\folder\main.js to a dynamic import() which is available in all CommonJS modules.
at Object. (C:\Users\user\Desktop\folder\main.js:5:18) {
code: 'ERR_REQUIRE_ESM'
}

I downgradedd to version 2.2.1 and it worked. What's the issue with the latest? I am using Node version 16.9.0

128 exit code

i'm not 100% sure, but isn't 128 a reserved code for an invalid argument provided to exit(3)?

Support for removing exit hooks

Issuehunt badges

Sometimes I want to register an exit-hook to if my program gets interrupted, etc. but in normal execution of the program resources are cleaned once they are no longer needed. It would be great to have support for removing an exit-hook if it is no longer needed. Thanks.


IssueHunt Summary

dflupu dflupu has been rewarded.

Backers (Total: $30.00)

Submitted pull Requests


Tips


IssueHunt has been backed by the following sponsors. Become a sponsor

Make `gracefulExit()` return a Promise

I think it would be useful if gracefulExit() could return a new Promise(() => {}). That would ease interrupting the execution flow without needing to do this manually everywhere. One could just ignore the return value if not needed. Do you think this is a good idea?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.