Skip to content

Commit

Permalink
feat: added ignoreHook log metadata option, updated types, switched t…
Browse files Browse the repository at this point in the history
…his.logger to this.config.logger, bumped deps
  • Loading branch information
titanism committed Nov 16, 2022
1 parent e670941 commit 1a260b7
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 49 deletions.
37 changes: 26 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,17 @@ const graceful = new Graceful({
timeoutMs: 5000,

// options to pass to `lil-http-terminator` to override defaults
lilHttpTerminator: {}
lilHttpTerminator: {},

//
// appends a `true` boolean value to a property of this name in the logger meta object
// (this is useful for Cabin/Axe as it will prevent a log from being created in MongoDB)
// (and instead of having a DB log created upon graceful exit, it will simply log to console)
// (defer to the Forward Email codebase, specifically the logger helper)
//
// NOTE: if you set this to `false` then this will be ignored and no meta property will be populated
//
ignoreHook: 'ignore_hook'
});

//
Expand Down Expand Up @@ -157,16 +167,17 @@ This package works with any server created with `http.createServer` or `net.crea

Here is the full list of options and their defaults. See [index.js](index.js) for more insight if necessary.

| Property | Type | Default Value | Description |
| ------------------- | ------ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `servers` | Array | `[]` | An array of HTTP or NET servers to gracefully close on exit |
| `brees` | Array | `[]` | An array of [Bree][] instances to gracefully exit |
| `redisClients` | Array | `[]` | An array of Redis client instances to gracefully exit |
| `mongooses` | Array | `[]` | An array of Mongoose connections to gracefully exit |
| `customHandlers` | Array | `[]` | An array of functions (custom handlers) to invoke upon graceful exit |
| `logger` | Object | `console` | This is the default logger. **We recommend using [Cabin][cabin]** instead of using `console` as your default logger. Set this value to `false` to disable logging entirely (uses noop function) |
| `timeoutMs` | Number | `5000` | A number in milliseconds for how long to wait to gracefully exit |
| `lilHttpTerminator` | Object | `{}` | An object of options to pass to `lil-http-terminator` to override default options provided |
| Property | Type | Default Value | Description |
| ------------------- | ------------------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `servers` | Array | `[]` | An array of HTTP or NET servers to gracefully close on exit |
| `brees` | Array | `[]` | An array of [Bree][] instances to gracefully exit |
| `redisClients` | Array | `[]` | An array of Redis client instances to gracefully exit |
| `mongooses` | Array | `[]` | An array of Mongoose connections to gracefully exit |
| `customHandlers` | Array | `[]` | An array of functions (custom handlers) to invoke upon graceful exit |
| `logger` | Object | `console` | This is the default logger. **We recommend using [Cabin][cabin]** instead of using `console` as your default logger. Set this value to `false` to disable logging entirely (uses noop function) |
| `timeoutMs` | Number | `5000` | A number in milliseconds for how long to wait to gracefully exit |
| `lilHttpTerminator` | Object | `{}` | An object of options to pass to `lil-http-terminator` to override default options provided |
| `ignoreHook` | String or `false` Boolean | `"ignore_hook"` | Appends a `true` boolean property to a property with this value in logs, e.g. `console.log('graceful exiting', { ignore_hook: true });` which is useful for preventing logs from being written to a database in hooks (this is meant for usage with [Cabin][] and [Axe][] and made for [Forward Email][forward-email]). If you pass a `false` value then this property will not get populated. |


## Examples
Expand Down Expand Up @@ -214,3 +225,7 @@ You can also read more about Bree at <https://github.com/breejs/bree>.
[cabin]: https://cabinjs.com

[bree]: https://jobscheduler.net

[axe]: https://github.com/cabinjs/axe

[forward-email]: https://github.com/forwardemail
13 changes: 7 additions & 6 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
interface Logger {
type Logger = {
info(): unknown;
warn(): unknown;
error(): unknown;
}
};

interface LilHttpTerminator {
type LilHttpTerminator = {
gracefulTerminationTimeout?: number;
maxWaitTimeout?: number;
logger?: Logger;
}
};

export interface GracefulOptions {
export type GracefulOptions = {
servers?: Array<{ close(): unknown }>;
brees?: Array<{ stop(): Promise<void> }>;
redisClients?: Array<{ disconnect(): unknown }>;
Expand All @@ -19,7 +19,8 @@ export interface GracefulOptions {
logger?: Logger;
timeoutMs?: number;
lilHttpTerminator?: LilHttpTerminator;
}
ignoreHook?: string | boolean;
};

export default class Graceful {
constructor(options?: GracefulOptions);
Expand Down
71 changes: 52 additions & 19 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class Graceful {
logger: console,
timeoutMs: 5000,
lilHttpTerminator: {},
ignoreHook: 'ignore_hook',
...config
};

Expand All @@ -30,12 +31,9 @@ class Graceful {
error() {}
};

// shortcut logger
this.logger = this.config.logger;

// if lilHttpTerminator does not have a logger set then re-use `this.logger`
// if lilHttpTerminator does not have a logger set then re-use `this.config.logger`
if (!this.config.lilHttpTerminator.logger)
this.config.lilHttpTerminator.logger = this.logger;
this.config.lilHttpTerminator.logger = this.config.logger;

// prevent multiple SIGTERM/SIGHUP/SIGINT from firing graceful exit
this._isExiting = false;
Expand Down Expand Up @@ -79,7 +77,7 @@ class Graceful {
process.on('warning', (warning) => {
// <https://github.com/pinojs/pino/issues/833#issuecomment-625192482>
warning.emitter = null;
this.logger.warn(warning);
this.config.logger.warn(warning);
});

// handle uncaught promises
Expand All @@ -95,15 +93,19 @@ class Graceful {

// handle uncaught exceptions
process.once('uncaughtException', (err) => {
this.logger.error(err);
this.config.logger.error(err);
process.exit(1);
});

// handle windows support (signals not available)
// <http://pm2.keymetrics.io/docs/usage/signals-clean-restart/#windows-graceful-stop>
process.on('message', async (message) => {
if (message === 'shutdown') {
this.logger.info('Received shutdown message');
if (this.config.ignoreHook)
this.config.logger.info('Received shutdown message', {
[this.config.ignoreHook]: true
});
else this.config.logger.info('Received shutdown message');
await this.exit();
}
});
Expand Down Expand Up @@ -139,7 +141,10 @@ class Graceful {
: util.promisify(server.close).bind(server)());
}
} catch (err) {
this.logger.error(err, { code });
this.config.logger.error(err, {
code,
...(this.config.ignoreHook ? { [this.config.ignoreHook]: true } : {})
});
}
}

Expand All @@ -154,7 +159,10 @@ class Graceful {
try {
await client.disconnect();
} catch (err) {
this.logger.error(err, { code });
this.config.logger.error(err, {
code,
...(this.config.ignoreHook ? { [this.config.ignoreHook]: true } : {})
});
}
}

Expand All @@ -170,7 +178,10 @@ class Graceful {
try {
await mongoose.disconnect();
} catch (err) {
this.logger.error(err, { code });
this.config.logger.error(err, {
code,
...(this.config.ignoreHook ? { [this.config.ignoreHook]: true } : {})
});
}
}

Expand All @@ -184,7 +195,10 @@ class Graceful {
try {
await bree.stop();
} catch (err) {
this.logger.error(err, { code });
this.config.logger.error(err, {
code,
...(this.config.ignoreHook ? { [this.config.ignoreHook]: true } : {})
});
}
}

Expand All @@ -198,7 +212,10 @@ class Graceful {
try {
await handler();
} catch (err) {
this.logger.error(err, { code });
this.config.logger.error(err, {
code,
...(this.config.ignoreHook ? { [this.config.ignoreHook]: true } : {})
});
}
}

Expand All @@ -211,22 +228,32 @@ class Graceful {
}

async exit(code) {
if (code) this.logger.info('Gracefully exiting', { code });
if (code)
this.config.logger.info('Gracefully exiting', {
code,
...(this.config.ignoreHook ? { [this.config.ignoreHook]: true } : {})
});

if (this._isExiting) {
this.logger.info('Graceful exit already in progress', { code });
this.config.logger.info('Graceful exit already in progress', {
code,
...(this.config.ignoreHook ? { [this.config.ignoreHook]: true } : {})
});
return;
}

this._isExiting = true;

// give it only X ms to gracefully exit
setTimeout(() => {
this.logger.error(
this.config.logger.error(
new Error(
`Graceful exit failed, timeout of ${this.config.timeoutMs}ms was exceeded`
),
{ code }
{
code,
...(this.config.ignoreHook ? { [this.config.ignoreHook]: true } : {})
}
);
// eslint-disable-next-line unicorn/no-process-exit
process.exit(1);
Expand All @@ -245,11 +272,17 @@ class Graceful {
// custom handlers
this.stopCustomHandlers(code)
]);
this.logger.info('Gracefully exited', { code });
this.config.logger.info('Gracefully exited', {
code,
...(this.config.ignoreHook ? { [this.config.ignoreHook]: true } : {})
});
// eslint-disable-next-line unicorn/no-process-exit
process.exit(0);
} catch (err) {
this.logger.error(err, { code });
this.config.logger.error(err, {
code,
...(this.config.ignoreHook ? { [this.config.ignoreHook]: true } : {})
});
// eslint-disable-next-line unicorn/no-process-exit
process.exit(1);
}
Expand Down
26 changes: 13 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,28 @@
"p-is-promise": "3"
},
"devDependencies": {
"@commitlint/cli": "^17.0.2",
"@commitlint/config-conventional": "^17.0.2",
"@ladjs/api": "^10.0.3",
"@ladjs/web": "^14.0.3",
"ava": "^4.3.0",
"@commitlint/cli": "^17.2.0",
"@commitlint/config-conventional": "^17.2.0",
"@ladjs/api": "^12.0.2",
"@ladjs/web": "^18.0.4",
"ava": "^5.1.0",
"cross-env": "^7.0.3",
"eslint": "8.17.0",
"eslint": "8.27.0",
"eslint-config-xo-lass": "^2.0.1",
"express": "^4.18.1",
"fastify": "^3.29.0",
"express": "^4.18.2",
"fastify": "^4.10.0",
"fixpack": "^4.0.0",
"get-port": "5",
"husky": "^8.0.1",
"ioredis": "^5.0.6",
"husky": "^8.0.2",
"ioredis": "^5.2.4",
"ioredis-mock": "^8.2.2",
"koa": "^2.13.4",
"lint-staged": "^13.0.0",
"lint-staged": "^13.0.3",
"nyc": "^15.1.0",
"remark-cli": "^10.0.1",
"remark-cli": "^11.0.0",
"remark-preset-github": "^4.0.4",
"smtp-server": "^3.11.0",
"xo": "^0.49.0"
"xo": "^0.52.4"
},
"engines": {
"node": ">=14"
Expand Down

0 comments on commit 1a260b7

Please sign in to comment.