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.
npm install exit-hook
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();
Register a function to run during process.exit
.
Returns a function that removes the hook when called.
Type: (signal: number) => void
The callback function to execute when the process exits.
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.
Type: (signal: number) => (void | Promise<void>)
The callback function to execute when the process exits via gracefulExit
, and will be wrapped in Promise.resolve
.
Type: object
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();
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();
Type: number
Default: 0
The exit code to use. Same as the argument to process.exit()
.
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
Forkers
mvayngrib tapppi stefanpenner fannarsh sanram dflupu tiagodanin-forks richienb julusian standardgalactic smeijer-forks brunoss8 yangxin1994 commonjs-bot omgimalexis jakobo terrorizer1980 michael-turchin paulovieira rpnzl scg82 geekwolverineexit-hook's Issues
Pass the signal to the hook?
Coming from node-cleanup
, I would like to see the signal passed to the hook.
Helps to know if the user pressed CTRL+C, vs. an unhandled rejection or exception occurred.
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?
Optional chaining requires Node 14+
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.
Repo "obsolete"
@Tapppi has done a great work in the async-exit-hook
fork.
Should we have to deprecate this repo in favor of the fork or should we have to merge everything here?
support multiple callbacks on one instance
it'd be cool if this lib only hooked onto these events once, but allowed multiple callbacks:
onexit(function() {
// do this
});
onexit(function() {
// do that
}
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
It does not catch 'nodemon' reload.
The hook does not catch 'nodemon' reloads. I am not sure if this is by design or not.
asyncExitHook API is documented incorrectly in readme
Readme documentation: asyncExitHook(onExit, minimumWait)
Implementation: asyncExitHook(onExit, { minimumWait: number })
Two ways to resolve this:
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;
}
Should `minimumWait` be `maximumWait` ?
Line 46 in 34078d9
Node will exit at (or before) forceAfter
ms, so I think it should called maximumWait
.
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)?
Comparison to signal-exit
Hello! I found this package and also signal-exit. Is there any practical difference?
I noticed you use signal-exit instead of this package in another of your modules (loud-rejection).
Thank you!
Support for removing exit hooks
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 has been rewarded.
Backers (Total: $30.00)
issuehunt ($30.00)
Submitted pull Requests
Tips
- Checkout the Issuehunt explorer to discover more funded issues.
- Need some help from other developers? Add your repositories on IssueHunt to raise funds.
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
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google โค๏ธ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.