From ec002dbb665a1a9661af35d47ffc390855747742 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 20 Aug 2025 15:41:19 +0000 Subject: [PATCH 1/4] Initial plan From c9ef48924dd9a6f7991f856061b6ac1ed1fe592b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 20 Aug 2025 15:59:10 +0000 Subject: [PATCH 2/4] Add signal parameter to onSignal function for better observability - Updated onSignal function to receive signal parameter (fixes #294) - Maintains backward compatibility with existing onSignal functions - Added TypeScript type definitions for optional signal parameter - Added comprehensive test coverage for new functionality - Created example demonstrating the new feature Co-authored-by: rxmarbles <9443787+rxmarbles@users.noreply.github.com> --- example/signal-parameter-example.js | 38 +++++++++++++++++++ .../terminus.onsignal.with-signal.js | 16 ++++++++ .../terminus.onsignal.with-signal.multiple.js | 18 +++++++++ lib/terminus.js | 2 +- lib/terminus.spec.js | 15 ++++++++ typings/index.d.ts | 2 +- typings/index.test.ts | 20 ++++++++++ 7 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 example/signal-parameter-example.js create mode 100644 lib/standalone-tests/terminus.onsignal.with-signal.js create mode 100644 lib/standalone-tests/terminus.onsignal.with-signal.multiple.js diff --git a/example/signal-parameter-example.js b/example/signal-parameter-example.js new file mode 100644 index 0000000..d481081 --- /dev/null +++ b/example/signal-parameter-example.js @@ -0,0 +1,38 @@ +'use strict' + +const http = require('http') +const { createTerminus } = require('@godaddy/terminus') + +// Create basic HTTP server +const server = http.createServer((req, res) => { + res.writeHead(200, { 'Content-Type': 'text/plain' }) + res.end('Server is running\n') +}) + +// Set up graceful shutdown with signal parameter +createTerminus(server, { + signal: 'SIGTERM', + onSignal: (signal) => { + console.log(`Received signal: ${signal}`) + console.log('Starting graceful shutdown...') + + // You can now track which signal triggered the shutdown + // for observability and monitoring purposes + if (signal === 'SIGTERM') { + console.log('Shutting down due to SIGTERM (likely from process manager)') + } else if (signal === 'SIGINT') { + console.log('Shutting down due to SIGINT (likely from Ctrl+C)') + } + + return Promise.resolve() + }, + onShutdown: () => { + console.log('Server shutdown complete') + return Promise.resolve() + } +}) + +server.listen(3000, () => { + console.log('Server listening on port 3000') + console.log('Send SIGTERM or SIGINT to trigger graceful shutdown') +}) diff --git a/lib/standalone-tests/terminus.onsignal.with-signal.js b/lib/standalone-tests/terminus.onsignal.with-signal.js new file mode 100644 index 0000000..2c84dce --- /dev/null +++ b/lib/standalone-tests/terminus.onsignal.with-signal.js @@ -0,0 +1,16 @@ +'use strict' +const http = require('http') +const server = http.createServer((req, res) => res.end('hello')) + +const { createTerminus } = require('../../') + +createTerminus(server, { + onSignal: (signal) => { + console.log('on-signal-runs:' + signal) + return Promise.resolve() + } +}) + +server.listen(8000, () => { + process.kill(process.pid, 'SIGTERM') +}) diff --git a/lib/standalone-tests/terminus.onsignal.with-signal.multiple.js b/lib/standalone-tests/terminus.onsignal.with-signal.multiple.js new file mode 100644 index 0000000..7c68b64 --- /dev/null +++ b/lib/standalone-tests/terminus.onsignal.with-signal.multiple.js @@ -0,0 +1,18 @@ +'use strict' +const http = require('http') +const server = http.createServer((req, res) => res.end('hello')) + +const { createTerminus } = require('../../') +const SIGNAL = process.argv[2] || 'SIGTERM' + +createTerminus(server, { + signal: SIGNAL, + onSignal: (signal) => { + console.log('on-signal-runs:' + signal) + return Promise.resolve() + } +}) + +server.listen(8000, () => { + process.kill(process.pid, SIGNAL) +}) diff --git a/lib/terminus.js b/lib/terminus.js index ef99905..3bee7ee 100644 --- a/lib/terminus.js +++ b/lib/terminus.js @@ -140,7 +140,7 @@ function decorateWithSignalHandler (server, state, options) { try { await beforeShutdown() await asyncServerStop() - await onSignal() + await onSignal(signal) await onShutdown() if (useExit0) { // Exit process diff --git a/lib/terminus.spec.js b/lib/terminus.spec.js index c27c52b..b2cfc33 100644 --- a/lib/terminus.spec.js +++ b/lib/terminus.spec.js @@ -1030,6 +1030,21 @@ describe('Terminus', () => { expect(result.stdout.toString().trim()).to.eql('on-sigusr2-runs\non-shutdown-runs') }) + it('passes signal parameter to onSignal function when killed with SIGTERM', () => { + const result = spawnSync('node', ['lib/standalone-tests/terminus.onsignal.with-signal.js']) + expect(result.stdout.toString().trim()).to.eql('on-signal-runs:SIGTERM') + }) + + it('passes signal parameter to onSignal function when killed with SIGINT', () => { + const result = spawnSync('node', ['lib/standalone-tests/terminus.onsignal.with-signal.multiple.js', 'SIGINT']) + expect(result.stdout.toString().trim()).to.eql('on-signal-runs:SIGINT') + }) + + it('passes signal parameter to onSignal function when killed with SIGUSR2', () => { + const result = spawnSync('node', ['lib/standalone-tests/terminus.onsignal.with-signal.multiple.js', 'SIGUSR2']) + expect(result.stdout.toString().trim()).to.eql('on-signal-runs:SIGUSR2') + }) + it('manages multiple servers', () => { const result = spawnSync('node', ['lib/standalone-tests/terminus.multiserver.js']) expect(result.stdout.toString().trim()).to.eql([ diff --git a/typings/index.d.ts b/typings/index.d.ts index 72521e8..da6d534 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -28,7 +28,7 @@ declare module "@godaddy/terminus" { statusError?: number, statusErrorResponse?: Record, useExit0?: boolean, - onSignal?: () => Promise; + onSignal?: (signal?: string) => Promise; onSendFailureDuringShutdown?: () => Promise; onShutdown?: () => Promise; beforeShutdown?: () => Promise; diff --git a/typings/index.test.ts b/typings/index.test.ts index a151433..3a356a5 100644 --- a/typings/index.test.ts +++ b/typings/index.test.ts @@ -37,3 +37,23 @@ const options: TerminusOptions = { createTerminus(server, options); server.listen(3000); + +// Test new signal parameter feature +async function onSignalWithParam(signal?: string) { + console.log('server is starting cleanup for signal:', signal); + return Promise.resolve(); +} + +const optionsWithSignalParam: TerminusOptions = { + onSignal: onSignalWithParam, + onShutdown, + logger: console.log +}; + +const serverWithSignalParam = http.createServer((request, response) => { + response.end('

Hello, World!

'); +}) + +createTerminus(serverWithSignalParam, optionsWithSignalParam); + +serverWithSignalParam.listen(3001); From 3ea1d77be335d755198a9cc91cbba7e9935aa2c7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 20 Aug 2025 16:49:30 +0000 Subject: [PATCH 3/4] Update README documentation for onSignal signal parameter Co-authored-by: rxmarbles <9443787+rxmarbles@users.noreply.github.com> --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1ed9634..168aefa 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,9 @@ npm i @godaddy/terminus --save const http = require('http'); const { createTerminus } = require('@godaddy/terminus'); -function onSignal () { +function onSignal (signal) { console.log('server is starting cleanup'); + console.log('received signal:', signal); return Promise.all([ // your clean logic, like closing database connections ]); @@ -68,7 +69,7 @@ const options = { useExit0, // [optional = false] instead of sending the received signal again without beeing catched, the process will exit(0) sendFailuresDuringShutdown, // [optional = true] whether or not to send failure (503) during shutdown beforeShutdown, // [optional] called before the HTTP server starts its shutdown - onSignal, // [optional] cleanup function, returning a promise (used to be onSigterm) + onSignal, // [optional] cleanup function, returning a promise (used to be onSigterm). Receives signal as parameter. onShutdown, // [optional] called right before exiting onSendFailureDuringShutdown, // [optional] called before sending each 503 during shutdowns From 7af68dc5be99c26b381b10c3b960eb261cf8b3e7 Mon Sep 17 00:00:00 2001 From: Rick Markins Date: Wed, 20 Aug 2025 09:59:16 -0700 Subject: [PATCH 4/4] Update typings/index.test.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- typings/index.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typings/index.test.ts b/typings/index.test.ts index 3a356a5..827cdfb 100644 --- a/typings/index.test.ts +++ b/typings/index.test.ts @@ -52,7 +52,7 @@ const optionsWithSignalParam: TerminusOptions = { const serverWithSignalParam = http.createServer((request, response) => { response.end('

Hello, World!

'); -}) +}); createTerminus(serverWithSignalParam, optionsWithSignalParam);