-
Notifications
You must be signed in to change notification settings - Fork 12
/
index.js
98 lines (84 loc) · 2.58 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
'use strict'
const fp = require('fastify-plugin')
const process = require('process')
const parallel = require('fastparallel')()
let registeredListeners = []
function fastifyGracefulShutdown(fastify, opts, next) {
const logger = fastify.log
? fastify.log.child({ plugin: 'fastify-graceful-shutdown' })
: undefined
const handlers = []
const timeout = opts.timeout || 10000
const signals = ['SIGINT', 'SIGTERM']
const handlerEventListener = opts.handlerEventListener || process
// Remove preexisting listeners if already created by previous instance of same plugin
if (opts.resetHandlersOnInit) {
registeredListeners.forEach(({ signal, listener }) => {
handlerEventListener.removeListener(signal, listener)
})
registeredListeners = []
}
for (let i = 0; i < signals.length; i++) {
let signal = signals[i]
if (handlerEventListener.listenerCount(signal) > 0) {
next(
new Error(
`${signal} handler was already registered use fastify.gracefulShutdown`,
),
)
return
}
}
function completed(err, signal) {
if (err) {
logger.error?.({ err: err, signal: signal }, 'process terminated')
// Avoid losing data
logger.flush?.()
handlerEventListener.exit(1)
} else {
logger.debug?.({ signal: signal }, 'process terminated')
// Avoid losing data
logger.flush?.()
handlerEventListener.exit(0)
}
}
function terminateAfterTimeout(signal, timeout) {
setTimeout(() => {
logger.error?.(
{ signal: signal, timeout: timeout },
'terminate process after timeout',
)
handlerEventListener.exit(1)
}, timeout).unref()
}
function shutdown(signal) {
parallel(null, handlers, signal, (err) => completed(err, signal))
}
function addHandler(handler) {
if (typeof handler !== 'function') {
throw new Error('Expected a function but got a ' + typeof handler)
}
handlers.push(handler)
}
fastify.decorate('gracefulShutdown', addHandler)
// shutdown fastify
addHandler((signal, cb) => {
logger.debug?.({ signal: signal }, 'triggering close hook')
fastify.close(cb)
})
// register handlers
signals.forEach((signal) => {
const listener = () => {
terminateAfterTimeout(signal, timeout)
logger.debug?.({ signal: signal }, 'received signal')
shutdown(signal)
}
registeredListeners.push({ signal, listener })
handlerEventListener.once(signal, listener)
})
next()
}
module.exports = fp(fastifyGracefulShutdown, {
fastify: '>=3.0.0',
name: 'fastify-graceful-shutdown',
})