Skip to content

Commit ba3f67f

Browse files
authored
feat(healthcheck): expose state to health checks (#185)
1 parent 5a442df commit ba3f67f

File tree

4 files changed

+53
-4
lines changed

4 files changed

+53
-4
lines changed

README.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ function onShutdown () {
3030
console.log('cleanup finished, server is shutting down');
3131
}
3232

33-
function healthCheck () {
33+
function healthCheck ({ state }) {
34+
// `state.isShuttingDown` (boolean) shows whether the server is shutting down or not
3435
return Promise.resolve(
3536
// optionally include a resolve value to be included as
3637
// info in the health check response
@@ -50,7 +51,7 @@ const server = http.createServer((request, response) => {
5051
const options = {
5152
// health check options
5253
healthChecks: {
53-
'/healthcheck': healthCheck, // a function returning a promise indicating service health,
54+
'/healthcheck': healthCheck, // a function accepting a state and returning a promise indicating service health,
5455
verbatim: true, // [optional = false] use object returned from /healthcheck verbatim in response,
5556
__unsafeExposeStackTraces: true // [optional = false] return stack traces in error response if healthchecks throw errors
5657
},

lib/standalone-tests/terminus.onsignal.nofail.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const SIGNAL = 'SIGINT'
77

88
createTerminus(server, {
99
healthChecks: {
10-
'/health': () => Promise.resolve()
10+
'/health': ({ state }) => Promise.resolve({ state })
1111
},
1212
sendFailuresDuringShutdown: false,
1313
signal: SIGNAL,

lib/terminus.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ function decorateWithHealthCheck (server, state, options) {
8585
}
8686
let info
8787
try {
88-
info = await healthCheck()
88+
info = await healthCheck({ state })
8989
} catch (error) {
9090
logger('healthcheck failed', error)
9191
return sendFailure(res, { error: error.causes, exposeStackTraces: healthChecks.__unsafeExposeStackTraces })

lib/terminus.spec.js

+48
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,54 @@ describe('Terminus', () => {
216216
expect(loggerRan).to.eql(true)
217217
})
218218

219+
it('exposes internal state (isShuttingDown: false) to health check', async () => {
220+
let onHealthCheckRan = false
221+
let exposedState
222+
223+
createTerminus(server, {
224+
healthChecks: {
225+
'/health': ({ state }) => {
226+
onHealthCheckRan = true
227+
exposedState = state
228+
return Promise.resolve()
229+
}
230+
}
231+
})
232+
server.listen(8000)
233+
234+
const response = await fetch('http://localhost:8000/health')
235+
expect(response.status).to.eql(200)
236+
expect(response.headers.has('Content-Type')).to.eql(true)
237+
expect(response.headers.get('Content-Type')).to.eql('application/json')
238+
expect(onHealthCheckRan).to.eql(true)
239+
expect(exposedState).to.eql({ isShuttingDown: false })
240+
})
241+
242+
it('exposes internal state (isShuttingDown: true) when shutting down', (done) => {
243+
let responseAssertionsComplete = false
244+
let exposedState
245+
246+
// We're only truly finished when the response has been analyzed and the forked http process has exited,
247+
// freeing up port 8000 for future tests
248+
execFile('node', ['lib/standalone-tests/terminus.onsignal.nofail.js'], (error) => {
249+
expect(error.signal).to.eql('SIGINT')
250+
expect(responseAssertionsComplete).to.eql(true)
251+
expect(exposedState).to.eql({ isShuttingDown: true })
252+
done()
253+
})
254+
255+
// let the process start up
256+
setTimeout(() => {
257+
fetch('http://localhost:8000/health')
258+
.then(async (res) => {
259+
expect(res.status).to.eql(200)
260+
responseAssertionsComplete = true
261+
const json = await res.json()
262+
exposedState = json.info.state
263+
})
264+
}, 300)
265+
})
266+
219267
describe('includes error on reject', async () => {
220268
const errors = [
221269
new Error('test error 1'),

0 commit comments

Comments
 (0)