1 | # async-exit-hook
|
2 | [![Build Status](https://api.travis-ci.org/Tapppi/async-exit-hook.svg)](https://travis-ci.org/Tapppi/async-exit-hook)
|
3 | [![Coverage Status](https://coveralls.io/repos/github/Tapppi/async-exit-hook/badge.svg?branch=master)](https://coveralls.io/github/Tapppi/async-exit-hook?branch=master)
|
4 |
|
5 | > Run some code when the process exits
|
6 |
|
7 | The `process.on('exit')` event doesn't catch all the ways a process can exit. This module catches:
|
8 |
|
9 | * process SIGINT, SIGTERM and SIGHUP, SIGBREAK signals
|
10 | * process beforeExit and exit events
|
11 | * PM2 clustering process shutdown message ([PM2 graceful reload](http://pm2.keymetrics.io/docs/usage/cluster-mode/#graceful-reload))
|
12 |
|
13 | Useful for cleaning up. You can also include async handlers, and add custom events to hook and exit on.
|
14 |
|
15 | Forked and pretty much rewritten from [exit-hook](https://npmjs.com/package/exit-hook).
|
16 |
|
17 |
|
18 | ## Install
|
19 |
|
20 | ```
|
21 | $ npm install --save async-exit-hook
|
22 | ```
|
23 |
|
24 | ## Usage
|
25 |
|
26 | ### Considerations and warning
|
27 | #### On `process.exit()` and asynchronous code
|
28 | **If you use asynchronous exit hooks, DO NOT use `process.exit()` to exit.
|
29 | The `exit` event DOES NOT support asynchronous code.**
|
30 | >['beforeExit' is not emitted for conditions causing explicit termination, such as process.exit()]
|
31 | (https://nodejs.org/api/process.html#process_event_beforeexit)
|
32 |
|
33 | #### Windows and `process.kill(signal)`
|
34 | On windows `process.kill(signal)` immediately kills the process, and does not fire signal events,
|
35 | and as such, cannot be used to gracefully exit. See *Clustering and child processes* for a
|
36 | workaround when killing child processes. I'm planning to support gracefully exiting
|
37 | with async support on windows soon.
|
38 |
|
39 | ### Clustering and child processes
|
40 | If you use custom clustering / child processes, you can gracefully shutdown your child process
|
41 | by sending a shutdown message (`childProc.send('shutdown')`).
|
42 |
|
43 | ### Example
|
44 | ```js
|
45 | const exitHook = require('async-exit-hook');
|
46 |
|
47 | exitHook(() => {
|
48 | console.log('exiting');
|
49 | });
|
50 |
|
51 | // you can add multiple hooks, even across files
|
52 | exitHook(() => {
|
53 | console.log('exiting 2');
|
54 | });
|
55 |
|
56 | // you can add async hooks by accepting a callback
|
57 | exitHook(callback => {
|
58 | setTimeout(() => {
|
59 | console.log('exiting 3');
|
60 | callback();
|
61 | }, 1000);
|
62 | });
|
63 |
|
64 | // You can hook uncaught errors with uncaughtExceptionHandler(), consequently adding
|
65 | // async support to uncaught errors (normally uncaught errors result in a synchronous exit).
|
66 | exitHook.uncaughtExceptionHandler(err => {
|
67 | console.error(err);
|
68 | });
|
69 |
|
70 | // You can add multiple uncaught error handlers
|
71 | // Add the second parameter (callback) to indicate async hooks
|
72 | exitHook.uncaughtExceptionHandler((err, callback) => {
|
73 | sendErrorToCloudOrWhatever(err, success => {
|
74 | if (err) {
|
75 | console.error('Error sending to cloud: ', err.stack);
|
76 | } else {
|
77 | console.log('Sent err to cloud');
|
78 | }
|
79 | callback();
|
80 | });
|
81 | });
|
82 |
|
83 | // Add exit hooks for a signal or custom message:
|
84 |
|
85 | // Custom signal
|
86 | // Arguments are `signal, exitCode` (SIGBREAK is already handled, this is an example)
|
87 | exitHook.hookEvent('SIGBREAK', 21);
|
88 |
|
89 | // process event: `message` with a filter
|
90 | // filter gets all arguments passed to *handler*: `process.on(message, *handler*)`
|
91 | // Exits on process event `message` with msg `customShutdownMessage` only
|
92 | exitHook.hookEvent('message', 0, msg => msg !== 'customShutdownMessage');
|
93 |
|
94 | // All async hooks will work with uncaught errors when you have specified an uncaughtExceptionHandler
|
95 | throw new Error('awesome');
|
96 |
|
97 | //=> // Sync uncaughtExcpetion hooks called and retun
|
98 | //=> '[Error: awesome]'
|
99 | //=> // Sync hooks called and retun
|
100 | //=> 'exiting'
|
101 | //=> 'exiting 2'
|
102 | //=> // Async uncaughtException hooks return
|
103 | //=> 'Sent error to cloud'
|
104 | //=> // Sync uncaughtException hooks return
|
105 | //=> 'exiting 3'
|
106 | ```
|
107 |
|
108 |
|
109 | ## License
|
110 |
|
111 | MIT © Tapani Moilanen
|
112 | MIT © [Sindre Sorhus](http://sindresorhus.com)
|