diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8268ae8..9d71e8a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ jobs: - name: Install run: | - npm install + npm install --ignore-scripts - name: Run tests run: | diff --git a/README.md b/README.md index 4b9ea28..d93d279 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,26 @@ closeWithGrace({ delay: 500 }, async function ({ signal, err, manual }) { }) ``` +### Injecting custom logger + +```js +const closeWithGrace = require('close-with-grace') + +// delay is the number of milliseconds for the graceful close to +// finish. +closeWithGrace( + { + delay: 500, + logger: { error: (m) => console.error(`[close-with-grace] ${m}`) } + }, + async function ({ signal, err, manual }) { + if (err) { + console.error(err) + } + await closeYourServer() +}) +``` + ## API ### `closeWithGrace([opts], fn({ err, signal, manual }))` @@ -42,6 +62,8 @@ If it is emitted again, it will terminate the process abruptly. * `delay`: the numbers of milliseconds before abruptly close the process. Default: `10000`. +* `logger`: instance of logger which will be used internally. Default: `10000`. + #### fn({ err, signal, manual } [, cb]) Execute the given function to perform a graceful close. diff --git a/index.d.ts b/index.d.ts index c9fea9f..9d2e21f 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,10 +1,19 @@ declare namespace closeWithGrace { + interface Logger { + error(message?: any, ...optionalParams: any[]): void + } + interface Options { /** * The numbers of milliseconds before abruptly close the process * @default 10000 */ - delay: number + delay?: number + /** + * Instance of logger which will be used internally + * @default console + */ + logger?: Logger } type Signals = "SIGTERM" | "SIGINT" diff --git a/index.js b/index.js index 82ce4be..8810530 100644 --- a/index.js +++ b/index.js @@ -11,6 +11,7 @@ function closeWithGrace (opts, fn) { opts = {} } const delay = opts.delay ? opts.delay : 10000 + const logger = opts.logger ? opts.logger : console process.once('SIGTERM', onSignal) process.once('SIGINT', onSignal) process.once('uncaughtException', onError) @@ -35,7 +36,7 @@ function closeWithGrace (opts, fn) { } function afterFirstSignal (signal) { - console.error(`second ${signal}, exiting`) + logger.error(`second ${signal}, exiting`) process.exit(1) } @@ -44,8 +45,8 @@ function closeWithGrace (opts, fn) { } function afterFirstError (err) { - console.error('second error, exiting') - console.error(err) + logger.error('second error, exiting') + logger.error(err) process.exit(1) } @@ -102,7 +103,7 @@ function closeWithGrace (opts, fn) { process.exit(0) } } catch (err) { - console.error(err) + logger.error(err) process.exit(1) } } diff --git a/index.test-d.ts b/index.test-d.ts index 1bbe14c..f4ea479 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -62,7 +62,10 @@ expectAssignable(WrongCallback) expectAssignable("SIGINT") expectAssignable("SIGTERM") -expectType({ delay: 10 }) +expectAssignable({ delay: 10 }) +expectAssignable({ logger: console }) +expectAssignable({ logger: console, delay: 10 }) +expectAssignable({ logger: { error: () => {} } }) expectAssignable<{ close: () => void diff --git a/test/close.test.js b/test/close.test.js index 6e49a1c..0c77999 100644 --- a/test/close.test.js +++ b/test/close.test.js @@ -127,6 +127,28 @@ for (const signal of ['SIGTERM', 'SIGINT']) { t.is(await err, `second ${signal}, exiting\n`) t.is(Date.now() - now < 500, true) }) + + test(`a secong signal (${signal}) calls custom logger`, async (t) => { + const child = fork(join(__dirname, 'no-resolve-custom-logger.js'), { + stdio: ['pipe', 'pipe', 'pipe', 'ipc'] + }) + + // one line to kickstart the test + await once(child.stderr, 'readable') + child.stderr.read() + t.pass('readable emitted') + + child.kill(signal) + + await once(child.stdout, 'readable') + + const err = all(child.stderr) + err.catch(() => {}) + + child.kill(signal) + + t.is(await err, `[custom logger] second ${signal}, exiting\n`) + }) } for (const event of ['uncaughtException', 'unhandledRejection']) { diff --git a/test/no-resolve-custom-logger.js b/test/no-resolve-custom-logger.js new file mode 100644 index 0000000..3d92ba3 --- /dev/null +++ b/test/no-resolve-custom-logger.js @@ -0,0 +1,19 @@ +'use strict' + +const closeWithGrace = require('..') + +const customLogger = { + error (message) { + console.error(`[custom logger] ${message}`) + } +} + +closeWithGrace({ delay: 500, logger: customLogger }, function ({ signal, err }) { + console.log('fn called') + // this promise never resolves, so the delay should kick in + return new Promise(() => {}) +}) + +// to keep the process open +setInterval(() => {}, 1000) +console.error(process.pid)