Comparing version 4.3.10 to 5.0.0
@@ -40,5 +40,6 @@ "use strict"; | ||
detectKubernetes: true, | ||
gracefulShutdownTimeout: 60000, | ||
port: 9000, | ||
signals: ['SIGTERM', 'SIGHUP', 'SIGINT'], | ||
timeout: 60000 | ||
shutdownHandlerTimeout: 5000, | ||
signals: ['SIGTERM', 'SIGHUP', 'SIGINT'] | ||
}; | ||
@@ -53,2 +54,6 @@ | ||
if (configuration.gracefulShutdownTimeout < configuration.shutdownHandlerTimeout) { | ||
throw new Error('gracefulShutdownTimeout cannot be lesser than shutdownHandlerTimeout.'); | ||
} | ||
let serverIsReady = false; | ||
@@ -119,10 +124,12 @@ let serverIsShuttingDown = false; | ||
log.info('received request to shutdown the service'); | ||
let gracefulShutdownTimeoutId; | ||
if (configuration.timeout !== Infinity) { | ||
setTimeout(() => { | ||
log.warn('timeout occurred before all the shutdown handlers could run to completion; forcing termination'); // eslint-disable-next-line no-process-exit | ||
if (configuration.gracefulShutdownTimeout !== Infinity) { | ||
gracefulShutdownTimeoutId = setTimeout(() => { | ||
log.warn('graceful shutdown timeout; forcing termination'); // eslint-disable-next-line no-process-exit | ||
process.exit(1); | ||
}, configuration.timeout) // $FlowFixMe | ||
.unref(); | ||
}, configuration.gracefulShutdownTimeout); // $FlowFixMe | ||
gracefulShutdownTimeoutId.unref(); | ||
} // @see https://github.com/gajus/lightship/issues/12 | ||
@@ -155,2 +162,18 @@ | ||
if (gracefulShutdownTimeoutId) { | ||
clearTimeout(gracefulShutdownTimeoutId); | ||
} | ||
let shutdownHandlerTimeoutId; | ||
if (configuration.shutdownHandlerTimeout !== Infinity) { | ||
shutdownHandlerTimeoutId = setTimeout(() => { | ||
log.warn('shutdown handler timeout; forcing termination'); // eslint-disable-next-line no-process-exit | ||
process.exit(1); | ||
}, configuration.shutdownHandlerTimeout); // $FlowFixMe | ||
shutdownHandlerTimeoutId.unref(); | ||
} | ||
log.debug('running %d shutdown handler(s)', shutdownHandlers.length); | ||
@@ -188,2 +211,6 @@ var _iteratorNormalCompletion = true; | ||
if (shutdownHandlerTimeoutId) { | ||
clearTimeout(shutdownHandlerTimeoutId); | ||
} | ||
log.debug('all shutdown handlers have run to completion; proceeding to terminate the Node.js process'); | ||
@@ -190,0 +217,0 @@ server.close(error => { |
@@ -87,3 +87,3 @@ { | ||
}, | ||
"version": "4.3.10" | ||
"version": "5.0.0" | ||
} |
@@ -20,2 +20,3 @@ <a name="lightship"></a> | ||
* [`/ready`](#lightship-behaviour-ready) | ||
* [Timeouts](#lightship-behaviour-timeouts) | ||
* [Usage](#lightship-usage) | ||
@@ -32,2 +33,3 @@ * [Kubernetes container probe configuration](#lightship-usage-kubernetes-container-probe-configuration) | ||
* [What is the reason for having separate `/live` and `/ready` endpoints?](#lightship-faq-what-is-the-reason-for-having-separate-live-and-ready-endpoints) | ||
* [How to detect what is holding the Node.js process alive?](#lightship-faq-how-to-detect-what-is-holding-the-node-js-process-alive) | ||
* [Related projects](#lightship-related-projects) | ||
@@ -84,2 +86,13 @@ | ||
<a name="lightship-behaviour-timeouts"></a> | ||
### Timeouts | ||
Lightship has two timeout configurations: `gracefulShutdownTimeout` (60 seconds) and `shutdownHandlerTimeout` (5 seconds). | ||
`gracefulShutdownTimeout` (default: 60 seconds) is a number of milliseconds Lightship waits for Node.js process to exit gracefully after it receives a shutdown signal (either via `process` or by calling `lightship.shutdown()`) before killing the process using `process.exit(1)`. This timeout should be sufficiently big to allow Node.js process to complete tasks (if any) that are active at the time that the shutdown signal is received (e.g. complete serving responses to all HTTP requests) (Note: You must explicitly inform Lightship about active tasks using [beacons](#beacons)). | ||
`shutdownHandlerTimeout` (default: 5 seconds) is a number of milliseconds Lightship waits for shutdown handlers (see `registerShutdownHandler`) to complete before killing the process using `process.exit(1)`. | ||
If after all beacons are dead and all shutdown handlers are resolved Node.js process does not exit gracefully, then Lightship will force terminate the process with an error. Refer to [How to detect what is holding the Node.js process alive?](#lightship-faq-how-to-detect-what-is-holding-the-node-js-process-alive). | ||
<a name="lightship-usage"></a> | ||
@@ -111,11 +124,13 @@ ## Usage | ||
* @property detectKubernetes Run Lightship in local mode when Kubernetes is not detected. Default: true. | ||
* @property gracefulShutdownTimeout A number of milliseconds before forcefull termination if process does not gracefully exit. The timer starts when `lightship.shutdown()` is called. This includes the time allowed to live beacons. Default: 60000. | ||
* @property port The port on which the Lightship service listens. This port must be different than your main service port, if any. The default port is 9000. | ||
* @property shutdownHandlerTimeout A number of milliseconds before forcefull termination if shutdown handlers do not complete. The timer starts when the first shutdown handler is called. Default: 5000. | ||
* @property signals An a array of [signal events]{@link https://nodejs.org/api/process.html#process_signal_events}. Default: [SIGTERM]. | ||
* @property timeout A number of milliseconds before forcefull termination. Default: 60000. | ||
*/ | ||
export type ConfigurationInputType = {| | ||
+detectKubernetes?: boolean, | ||
+gracefulShutdownTimeout?: number, | ||
+port?: number, | ||
+shutdownHandlerTimeout?: number, | ||
+signals?: $ReadOnlyArray<string>, | ||
+timeout?: number | ||
|}; | ||
@@ -353,3 +368,3 @@ | ||
Beacon is live upon creation. Shutdown handlers are suspended until there are live beacons. | ||
Beacon is live upon creation. Shutdown handlers are suspended until there are no live beacons. | ||
@@ -475,2 +490,46 @@ To singnal that a beacon is dead, use `die()` method: | ||
<a name="lightship-faq-how-to-detect-what-is-holding-the-node-js-process-alive"></a> | ||
### How to detect what is holding the Node.js process alive? | ||
You may get a log message saying that your process did not exit on its own, e.g. | ||
``` | ||
[2019-11-10T21:11:45.452Z] DEBUG (20) (@lightship) (#factories/createLightship): all shutdown handlers have run to completion; proceeding to terminate the Node.js process | ||
[2019-11-10T21:11:46.455Z] WARN (40) (@lightship) (#factories/createLightship): process did not exit on its own; investigate what is keeping the event loop active | ||
``` | ||
This means that there is some work that is scheduled to happen (e.g. a referenced `setTimeout`). | ||
In order to understand what is keeping your Node.js process from exiting on its own, you need to identify all active handles and requests. This can be done with a help of utilities such as [`wtfnode`](https://www.npmjs.com/package/wtfnode) and [`why-is-node-running`](https://www.npmjs.com/package/why-is-node-running), e.g. | ||
```js | ||
import whyIsNodeRunning from 'why-is-node-running'; | ||
import express from 'express'; | ||
import { | ||
createLightship | ||
} from 'lightship'; | ||
const app = express(); | ||
app.get('/', (req, res) => { | ||
res.send('Hello, World!'); | ||
}); | ||
const server = app.listen(8080); | ||
const lightship = createLightship(); | ||
lightship.registerShutdownHandler(() => { | ||
server.close(); | ||
whyIsNodeRunning(); | ||
}); | ||
lightship.signalReady(); | ||
``` | ||
In the above example, calling `whyIsNodeRunning` will print a list of all active handles that are keeping the process alive. | ||
<a name="lightship-related-projects"></a> | ||
@@ -477,0 +536,0 @@ ## Related projects |
@@ -33,3 +33,5 @@ // @flow | ||
detectKubernetes: true, | ||
gracefulShutdownTimeout: 60000, | ||
port: 9000, | ||
shutdownHandlerTimeout: 5000, | ||
signals: [ | ||
@@ -40,3 +42,2 @@ 'SIGTERM', | ||
], | ||
timeout: 60000, | ||
}; | ||
@@ -56,2 +57,6 @@ | ||
if (configuration.gracefulShutdownTimeout < configuration.shutdownHandlerTimeout) { | ||
throw new Error('gracefulShutdownTimeout cannot be lesser than shutdownHandlerTimeout.'); | ||
} | ||
let serverIsReady = false; | ||
@@ -131,12 +136,14 @@ let serverIsShuttingDown = false; | ||
if (configuration.timeout !== Infinity) { | ||
setTimeout(() => { | ||
log.warn('timeout occurred before all the shutdown handlers could run to completion; forcing termination'); | ||
let gracefulShutdownTimeoutId; | ||
if (configuration.gracefulShutdownTimeout !== Infinity) { | ||
gracefulShutdownTimeoutId = setTimeout(() => { | ||
log.warn('graceful shutdown timeout; forcing termination'); | ||
// eslint-disable-next-line no-process-exit | ||
process.exit(1); | ||
}, configuration.timeout) | ||
}, configuration.gracefulShutdownTimeout); | ||
// $FlowFixMe | ||
.unref(); | ||
// $FlowFixMe | ||
gracefulShutdownTimeoutId.unref(); | ||
} | ||
@@ -172,2 +179,20 @@ | ||
if (gracefulShutdownTimeoutId) { | ||
clearTimeout(gracefulShutdownTimeoutId); | ||
} | ||
let shutdownHandlerTimeoutId; | ||
if (configuration.shutdownHandlerTimeout !== Infinity) { | ||
shutdownHandlerTimeoutId = setTimeout(() => { | ||
log.warn('shutdown handler timeout; forcing termination'); | ||
// eslint-disable-next-line no-process-exit | ||
process.exit(1); | ||
}, configuration.shutdownHandlerTimeout); | ||
// $FlowFixMe | ||
shutdownHandlerTimeoutId.unref(); | ||
} | ||
log.debug('running %d shutdown handler(s)', shutdownHandlers.length); | ||
@@ -185,2 +210,6 @@ | ||
if (shutdownHandlerTimeoutId) { | ||
clearTimeout(shutdownHandlerTimeoutId); | ||
} | ||
log.debug('all shutdown handlers have run to completion; proceeding to terminate the Node.js process'); | ||
@@ -187,0 +216,0 @@ |
@@ -14,11 +14,13 @@ // @flow | ||
* @property detectKubernetes Run Lightship in local mode when Kubernetes is not detected. Default: true. | ||
* @property gracefulShutdownTimeout A number of milliseconds before forcefull termination if process does not gracefully exit. The timer starts when `lightship.shutdown()` is called. This includes the time allowed to live beacons and shutdown handlers. Default: 60000. | ||
* @property port The port on which the Lightship service listens. This port must be different than your main service port, if any. The default port is 9000. | ||
* @property shutdownHandlerTimeout A number of milliseconds before forcefull termination if shutdown handlers do not complete. The timer starts when the first shutdown handler is called. Default: 5000. | ||
* @property signals An a array of [signal events]{@link https://nodejs.org/api/process.html#process_signal_events}. Default: [SIGTERM]. | ||
* @property timeout A number of milliseconds before forcefull termination. Default: 60000. | ||
*/ | ||
export type ConfigurationInputType = {| | ||
+detectKubernetes?: boolean, | ||
+gracefulShutdownTimeout?: number, | ||
+port?: number, | ||
+shutdownHandlerTimeout?: number, | ||
+signals?: $ReadOnlyArray<string>, | ||
+timeout?: number, | ||
|}; | ||
@@ -28,5 +30,6 @@ | ||
+detectKubernetes: boolean, | ||
+gracefulShutdownTimeout: number, | ||
+port: number, | ||
+shutdownHandlerTimeout: number, | ||
+signals: $ReadOnlyArray<string>, | ||
+timeout: number, | ||
|}; | ||
@@ -33,0 +36,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
72783
627
534