Skip to content

Commit a33ab47

Browse files
committed
Fix uncaughtException exit
1 parent 9f98c4b commit a33ab47

File tree

3 files changed

+26
-23
lines changed

3 files changed

+26
-23
lines changed

README.md

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ logProcessErrors(options)
2626
`options` is an optional object with the following properties:
2727

2828
- [`log` `{function}`](#custom-logging)
29-
- [`exitOnExceptions` `{boolean}`](#exiting-on-uncaught-exceptions) (default:
30-
`true`)
3129
- [`getLevel` `{function}`](#log-level)
3230
- [`getMessage` `{function}`](#log-message)
3331
- [`colors` `{boolean}`](#log-message) (default: `false`)
@@ -80,21 +78,6 @@ The function's arguments are:
8078
`rejectionHandled` and `multipleResolves`
8179
- `secondPromiseState`, `secondPromiseValue`: only on `multipleResolves`
8280

83-
# Exiting on uncaught exceptions
84-
85-
By default `uncaughtException` will fire `process.exit(1)`. This is the
86-
recommended behavior according to the
87-
[Node.js documentation](https://nodejs.org/api/process.html#process_warning_using_uncaughtexception_correctly).
88-
89-
This can disabled by setting the `exitOnExceptions` option to `false`:
90-
91-
<!-- eslint-disable no-empty-function, no-unused-vars, node/no-missing-require,
92-
import/no-unresolved, unicorn/filename-case, strict, no-undef -->
93-
94-
```js
95-
logProcessErrors({ exitOnExceptions: false })
96-
```
97-
9881
# Log level
9982

10083
By default the log level will be `warn` for `warning` events and `error` for
@@ -150,6 +133,16 @@ logProcessErrors({
150133
})
151134
```
152135

136+
# Uncaught exceptions
137+
138+
`uncaughtException` events will fire `process.exit(1)`. This is the recommended
139+
behavior according to the
140+
[Node.js documentation](https://nodejs.org/api/process.html#process_warning_using_uncaughtexception_correctly).
141+
142+
`process.exit(1)` will only be fired after the `uncaughtException` event has
143+
been logged. If an custom `log` option is used and it is asynchronous, the
144+
function should return a promise (or use `async`/`await`).
145+
153146
# Stop logging
154147

155148
Logging can be stopped by firing the function returned by `logProcessErrors()`

src/default.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ const DEFAULT_OPTS = {
99
getLevel: defaultGetLevel,
1010
getMessage: defaultGetMessage,
1111
log: defaultLog,
12-
exitOnExceptions: true,
1312
colors: true,
1413
}
1514

src/handle.js

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict'
22

33
const { exit } = require('process')
4+
const { promisify } = require('util')
45

56
const { getInfo } = require('./info')
67
const { getColors } = require('./colors')
@@ -34,22 +35,32 @@ const handleEvent = async function({
3435
const level = getLevel({ opts, info })
3536
const message = getMessage({ opts, info, level, colors })
3637

37-
opts.log(message, level, info)
38+
// We need to `await` it in case we are logging an `uncaughtException` which
39+
// will make the process exit.
40+
// Without `await` Node.js would still wait until most async tasks (including
41+
// stream draining for logging libraries like Winston) have completed.
42+
// But there are some cases where it will not. In those cases, `opts.log()`
43+
// should be either synchronous or return a promise.
44+
await opts.log(message, level, info)
3845

39-
exitProcess({ eventName, opts })
46+
await exitProcess({ eventName })
4047
}
4148

4249
// Exit process on `uncaughtException`
4350
// See https://nodejs.org/api/process.html#process_warning_using_uncaughtexception_correctly
44-
// Can be disabled with `opts.exitOnExceptions: false`
45-
const exitProcess = function({ eventName, opts: { exitOnExceptions } }) {
46-
if (eventName !== 'uncaughtException' || !exitOnExceptions) {
51+
const exitProcess = async function({ eventName }) {
52+
if (eventName !== 'uncaughtException') {
4753
return
4854
}
4955

56+
// This is only needed as a safety measure
57+
await promisify(setTimeout)(EXIT_TIMEOUT)
58+
5059
exit(1)
5160
}
5261

62+
const EXIT_TIMEOUT = 3e3
63+
5364
module.exports = {
5465
handleEvent,
5566
}

0 commit comments

Comments
 (0)