Skip to content

Commit

Permalink
Merge branch 'master' into hsubra89/respond-to-head-requests
Browse files Browse the repository at this point in the history
  • Loading branch information
gajus authored Oct 18, 2022
2 parents 6f61a93 + 78b1b72 commit 220759c
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 11 deletions.
4 changes: 2 additions & 2 deletions .README/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Used to configure readiness probe.

Lightship has two timeout configurations: `gracefulShutdownTimeout` and `shutdownHandlerTimeout`.

`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)).
`gracefulShutdownTimeout` (default: 30 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)`.

Expand Down Expand Up @@ -90,7 +90,7 @@ type ShutdownHandler = () => Promise<void> | void;

/**
* @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 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: 30000.
* @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. The default can be overwritten using LIGHTSHIP_PORT environment variable.
* @property shutdownDelay Delays the shutdown handler by X milliseconds. This value should match `readinessProbe.periodSeconds`. Default 5000.
* @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.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ Used to configure readiness probe.

Lightship has two timeout configurations: `gracefulShutdownTimeout` and `shutdownHandlerTimeout`.

`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)).
`gracefulShutdownTimeout` (default: 30 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)`.

Expand Down Expand Up @@ -120,7 +120,7 @@ type ShutdownHandler = () => Promise<void> | void;

/**
* @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 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: 30000.
* @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. The default can be overwritten using LIGHTSHIP_PORT environment variable.
* @property shutdownDelay Delays the shutdown handler by X milliseconds. This value should match `readinessProbe.periodSeconds`. Default 5000.
* @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.
Expand Down
23 changes: 16 additions & 7 deletions src/factories/createLightship.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const {

const defaultConfiguration: Configuration = {
detectKubernetes: true,
gracefulShutdownTimeout: 60_000,
gracefulShutdownTimeout: 30_000,
port: LIGHTSHIP_PORT ? Number(LIGHTSHIP_PORT) : 9_000,
shutdownDelay: 5_000,
shutdownHandlerTimeout: 5_000,
Expand All @@ -63,12 +63,11 @@ export default async (userConfiguration?: ConfigurationInput): Promise<Lightship
let blockingTasks: BlockingTask[] = [];

let resolveFirstReady: () => void;
const deferredFirstReady = new Promise<void>((resolve) => {
resolveFirstReady = resolve;
});
let rejectFirstReady: () => void;

void deferredFirstReady.then(() => {
log.info('service became available for the first time');
const deferredFirstReady = new Promise<void>((resolve, reject) => {
resolveFirstReady = resolve;
rejectFirstReady = reject;
});

const eventEmitter = new EventEmitter();
Expand Down Expand Up @@ -321,6 +320,16 @@ export default async (userConfiguration?: ConfigurationInput): Promise<Lightship
};
};

void deferredFirstReady.then(() => {
log.info('service became available for the first time');
}).catch((error) => {
log.error({
error: serializeError(error),
}, 'service failed to become available for the first time');

return shutdown(false);
});

return {
createBeacon,
isServerReady,
Expand All @@ -338,7 +347,7 @@ export default async (userConfiguration?: ConfigurationInput): Promise<Lightship
if (blockingTasks.length === 0 && serverIsReady === true) {
resolveFirstReady();
}
});
}).catch(rejectFirstReady);
},
registerShutdownHandler: (shutdownHandler) => {
shutdownHandlers.push(shutdownHandler);
Expand Down
29 changes: 29 additions & 0 deletions test/lightship/factories/createLightship.ts
Original file line number Diff line number Diff line change
Expand Up @@ -496,3 +496,32 @@ test('delays shutdown handlers', async (t) => {
t.is(terminate.called, false);
});

test('errors produced by blocking tasks causes a service shutdown', async (t) => {
const terminate = stub();

const lightship = await createLightship({
shutdownDelay: 0,
terminate,
});

let rejectBlockingTask: (() => void) | undefined;

const blockingTask = new Promise<void>((resolve, reject) => {
rejectBlockingTask = reject;
});

lightship.queueBlockingTask(blockingTask);

lightship.signalReady();

t.is(lightship.isServerReady(), false);

if (rejectBlockingTask) {
rejectBlockingTask();
}

await delay(0);

t.is(lightship.isServerShuttingDown(), true);
t.is(lightship.isServerReady(), false);
});

0 comments on commit 220759c

Please sign in to comment.