diff --git a/node-health/src/readiness.ts b/node-health/src/readiness.ts index 1423a1a..9bde26b 100644 --- a/node-health/src/readiness.ts +++ b/node-health/src/readiness.ts @@ -1,5 +1,5 @@ -/** Return type of a readiness check function */ -export type ReadinessFunctionReturn = { +/** Readiness check function return type */ +export type ReadinessReturn = { /** Status of the readiness check */ status: ReadinessStatus; /** Optional message providing additional information about the readiness check */ @@ -7,45 +7,47 @@ export type ReadinessFunctionReturn = { }; /** Function that performs a readiness check */ -export type ReadinessFunction = (check: ReadinessCheck) => Promise; +export type ReadinessCheckFn = (check: ReadinessCheck) => Promise; -/** Status of a readiness check */ -export type ReadinessStatus = 'ok' | 'error' | 'degraded'; +/** Status of the service readiness */ +export type ReadinessStatus = 'fatal' | 'not_ready' | 'degraded' | 'ready'; -const aggregateStatus = (statuses: ReadinessStatus[]): ReadinessStatus => { - if (statuses.includes('error')) return 'error'; +/** Returns the worst readiness status from a list of statuses. */ +const worstStatus = (statuses: ReadinessStatus[]): ReadinessStatus => { + if (statuses.includes('fatal')) return 'fatal'; + if (statuses.includes('not_ready')) return 'not_ready'; if (statuses.includes('degraded')) return 'degraded'; - return 'ok'; + return 'ready'; }; -/** Represents a readiness check with an optional timeout */ +/** Individual readiness check */ export type ReadinessCheck = { /** Name of the readiness check */ name: string; /** Function that performs the readiness check */ - fn: ReadinessFunction; + fn: ReadinessCheckFn; /** Timeout in milliseconds for the readiness check (default: 5000) */ timeout?: number; }; -/** Result of a system readiness check */ -export type ReadinessResult = { +/** System readiness status */ +export type Readiness = { /** * Status of the system readiness check, aggregated as the worst status - * among individual checks. 'unknown' is a special case indicating that - * no checks were performed, used by ScheduledReadiness before the first run. - * */ - status: ReadinessStatus | 'unknown'; + * among individual checks. If no checks have been performed yet, the status + * is 'not_ready'. + */ + status: ReadinessStatus; /** Start time of the system readiness check in milliseconds since the Unix epoch */ start: number; /** Duration of the system readiness check in milliseconds */ duration: number; /** Details of individual readiness checks */ - details: ReadinessDetail[]; + details: ReadinessCheckResult[]; }; -/** Detail of an individual readiness check */ -export type ReadinessDetail = { +/** System-generated result from an individual readiness check */ +export type ReadinessCheckResult = { /** Name of the readiness check */ name: string; /** Status of the readiness check */ @@ -59,12 +61,12 @@ export type ReadinessDetail = { /** * Performs a readiness check by executing the provided readiness functions. * @param checks - An array of readiness functions to execute. - * @returns A Promise that resolves to a ReadinessResult object. + * @returns A Promise that resolves to a Readiness object. */ -export const readiness = async (checks: ReadinessCheck[]): Promise => { +export const readiness = async (checks: ReadinessCheck[]): Promise => { const start = Date.now(); const t0 = performance.now(); - const details: ReadinessDetail[] = []; + const details: ReadinessCheckResult[] = []; for (const check of checks) { const checkt0 = performance.now(); @@ -83,7 +85,7 @@ export const readiness = async (checks: ReadinessCheck[]): Promise d.status)), + status: worstStatus(details.map((d) => d.status)), start, duration, details, @@ -104,7 +106,7 @@ export const readiness = async (checks: ReadinessCheck[]): Promise Promise) => { return async () => { @@ -121,8 +123,8 @@ export class ScheduledReadiness { private interval: number; private started: boolean = false; private timer: NodeJS.Timeout | null = null; - private latestResult: ReadinessResult | null = null; - private nextResult: Promise | null = null; + private latestResult: Readiness | null = null; + private nextResult: Promise | null = null; /** * Creates an instance of ScheduledReadiness. @@ -165,7 +167,7 @@ export class ScheduledReadiness { } /** Gets the next readiness result, waiting if a check is in progress */ - async getNextResult(): Promise { + async getNextResult(): Promise { if (this.nextResult) { return await this.nextResult; } @@ -173,7 +175,7 @@ export class ScheduledReadiness { } /** Gets the latest readiness result without waiting */ - getResult(): ReadinessResult | null { + getResult(): Readiness | null { return this.latestResult; } @@ -192,7 +194,7 @@ export class ScheduledReadiness { /** * Creates a handler function for readiness HTTP requests using the latest scheduled result. * Scheduled handler always returns the most recent result, or 'unknown' if no checks have run yet. - * @returns A function that returns a Response object with ReadinessResult in JSON format. + * @returns A function that returns a Response object with Readiness in JSON format. */ createHandler(): () => Promise { return async () => { @@ -200,13 +202,13 @@ export class ScheduledReadiness { if (!result) { return new Response( JSON.stringify({ - status: 'unknown', + status: 'not_ready', start: Date.now(), duration: 0, details: [], - } as ReadinessResult), + } as Readiness), { - status: httpStatusFromReadiness('unknown'), + status: httpStatusFromReadiness('not_ready'), headers: { 'Content-Type': 'application/json' }, }, ); @@ -217,8 +219,8 @@ export class ScheduledReadiness { } } -/** Returns a Response object with the given ReadinessResult in JSON format */ -const respondWithResult = (result: ReadinessResult) => { +/** Returns a Response object with the given Readiness in JSON format */ +const respondWithResult = (result: Readiness) => { return new Response(JSON.stringify(result), { status: httpStatusFromReadiness(result.status), headers: { 'Content-Type': 'application/json' }, @@ -226,11 +228,11 @@ const respondWithResult = (result: ReadinessResult) => { }; /** Returns the HTTP status code corresponding to a given readiness status */ -const httpStatusFromReadiness = (status: ReadinessStatus | 'unknown'): number => { - if (status === 'ok') return 200; +const httpStatusFromReadiness = (status: ReadinessStatus): number => { + if (status === 'ready') return 200; if (status === 'degraded') return 200; // 206 could also be suitable, but let's avoid false alarms - if (status === 'error') return 503; - return 200; // unknown, treat as ok to avoid false alarms + if (status === 'fatal') return 503; + return 200; // not_ready, treat as ok to avoid false alarms }; const withTimeout = async (