Skip to content

Commit af62cbe

Browse files
authored
feat(shutdown): sendFailuresDuringShutdown flag (#172)
Adds new boolean flag, `sendFailuresDuringShutdown`. If set to `false`, health check will continue checking and responding while shutting down, instead of sending 503s once it receives a signal. Defaults to `true`, maintaining current behavior as the default. Fixes #112
1 parent f4d348c commit af62cbe

File tree

6 files changed

+97
-2
lines changed

6 files changed

+97
-2
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ const options = {
6161
timeout: 1000, // [optional = 1000] number of milliseconds before forceful exiting
6262
signal, // [optional = 'SIGTERM'] what signal to listen for relative to shutdown
6363
signals, // [optional = []] array of signals to listen for relative to shutdown
64+
sendFailuresDuringShutdown, // [optional = true] whether or not to send failure (503) during shutdown
6465
beforeShutdown, // [optional] called before the HTTP server starts its shutdown
6566
onSignal, // [optional] cleanup function, returning a promise (used to be onSigterm)
6667
onShutdown, // [optional] called right before exiting
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
'use strict'
2+
const http = require('http')
3+
const server = http.createServer((req, res) => res.end('hello'))
4+
5+
const { createTerminus } = require('../../')
6+
7+
createTerminus(server, {
8+
healthChecks: {
9+
'/health': () => Promise.resolve()
10+
},
11+
sendFailuresDuringShutdown: false,
12+
onSendFailureDuringShutdown: async () => {
13+
console.log('onSendFailureDuringShutdown')
14+
},
15+
beforeShutdown: () => {
16+
return new Promise((resolve) => {
17+
setTimeout(resolve, 1000)
18+
})
19+
}
20+
})
21+
22+
server.listen(8000, () => {
23+
process.kill(process.pid, 'SIGTERM')
24+
})
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
'use strict'
2+
const http = require('http')
3+
const server = http.createServer((req, res) => res.end('hello'))
4+
5+
const { createTerminus } = require('../../')
6+
const SIGNAL = 'SIGINT'
7+
8+
createTerminus(server, {
9+
healthChecks: {
10+
'/health': () => Promise.resolve()
11+
},
12+
sendFailuresDuringShutdown: false,
13+
signal: SIGNAL,
14+
beforeShutdown: () => {
15+
return new Promise((resolve) => {
16+
setTimeout(resolve, 1000)
17+
})
18+
}
19+
})
20+
21+
server.listen(8000, () => {
22+
process.kill(process.pid, SIGNAL)
23+
})

lib/terminus.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,14 @@ const intialState = {
5858
function noop () {}
5959

6060
function decorateWithHealthCheck (server, state, options) {
61-
const { healthChecks, logger, onSendFailureDuringShutdown, caseInsensitive } = options
61+
const { healthChecks, logger, onSendFailureDuringShutdown, sendFailuresDuringShutdown, caseInsensitive } = options
6262

6363
let hasSetHandler = false
6464
const createHandler = (listener) => {
6565
const check = hasSetHandler
6666
? () => {}
6767
: async (healthCheck, res) => {
68-
if (state.isShuttingDown) {
68+
if (state.isShuttingDown && sendFailuresDuringShutdown) {
6969
return sendFailure(res, { onSendFailureDuringShutdown })
7070
}
7171
let info
@@ -142,6 +142,7 @@ function terminus (server, options = {}) {
142142
signals = [],
143143
timeout = 1000,
144144
healthChecks = {},
145+
sendFailuresDuringShutdown = true,
145146
onSendFailureDuringShutdown,
146147
onShutdown = noopResolves,
147148
beforeShutdown = noopResolves,
@@ -155,6 +156,7 @@ function terminus (server, options = {}) {
155156
decorateWithHealthCheck(server, state, {
156157
healthChecks,
157158
logger,
159+
sendFailuresDuringShutdown,
158160
onSendFailureDuringShutdown,
159161
caseInsensitive
160162
})

lib/terminus.spec.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,50 @@ describe('Terminus', () => {
323323
})
324324
})
325325

326+
it('does not return 503 once signal received if `sendFailuresDuringShutdown` is `false`', (done) => {
327+
let responseAssertionsComplete = false
328+
329+
// We're only truly finished when the response has been analyzed and the forked http process has exited,
330+
// freeing up port 8000 for future tests
331+
execFile('node', ['lib/standalone-tests/terminus.onsignal.nofail.js'], (error) => {
332+
expect(error.signal).to.eql('SIGINT')
333+
expect(responseAssertionsComplete).to.eql(true)
334+
done()
335+
})
336+
337+
// let the process start up
338+
setTimeout(() => {
339+
fetch('http://localhost:8000/health')
340+
.then(res => {
341+
expect(res.status).to.eql(200)
342+
responseAssertionsComplete = true
343+
})
344+
}, 300)
345+
})
346+
347+
it('does not call onSendFailureDuringShutdown if `sendFailuresDuringShutdown` is `false`', (done) => {
348+
let responseAssertionsComplete = false
349+
350+
// We're only truly finished when the response has been analyzed and the forked http process has exited,
351+
// freeing up port 8000 for future tests
352+
execFile('node', ['lib/standalone-tests/terminus.nofailuresduringshutdown.js'],
353+
(error, stdout) => {
354+
expect(error.signal).to.eql('SIGTERM')
355+
expect(stdout).to.eql('')
356+
expect(responseAssertionsComplete).to.eql(true)
357+
done()
358+
})
359+
360+
// let the process start up
361+
setTimeout(() => {
362+
fetch('http://localhost:8000/health')
363+
.then(res => {
364+
expect(res.status).to.eql(200)
365+
responseAssertionsComplete = true
366+
})
367+
}, 300)
368+
})
369+
326370
it('runs onSignal when getting the SIGTERM signal', () => {
327371
const result = spawnSync('node', ['lib/standalone-tests/terminus.onsigterm.js'])
328372
expect(result.stdout.toString().trim()).to.eql('on-sigterm-runs')

typings/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ declare module "@godaddy/terminus" {
1919
timeout?: number;
2020
signal?: string;
2121
signals?: string[];
22+
sendFailuresDuringShutdown?: boolean;
2223
onSignal?: () => Promise<any>;
2324
onSendFailureDuringShutdown?: () => Promise<any>;
2425
onShutdown?: () => Promise<any>;

0 commit comments

Comments
 (0)