UNPKG

@loopback/health

Version:

An extension exposes health check related endpoints with LoopBack 4

89 lines (78 loc) 2.98 kB
// Copyright IBM Corp. and LoopBack contributors 2019,2020. All Rights Reserved. // Node module: @loopback/health // This file is licensed under the MIT License. // License text available at https://opensource.org/licenses/MIT import { HealthChecker, LivenessCheck, ReadinessCheck, ShutdownCheck, StartupCheck, } from '@cloudnative/health'; import { ContextView, filterByTag, inject, LifeCycleObserver, } from '@loopback/core'; import {EventEmitter, once as onceGeneric} from 'events'; import {HealthBindings, HealthTags} from '../keys'; import {LiveCheck, ReadyCheck} from '../types'; export class HealthObserver implements LifeCycleObserver { private eventEmitter = new EventEmitter(); private startupCheck: Promise<void>; private shutdownCheck: ShutdownCheck; constructor( @inject(HealthBindings.HEALTH_CHECKER) private healthChecker: HealthChecker, @inject.view(filterByTag(HealthTags.LIVE_CHECK)) private liveChecks: ContextView<LiveCheck>, @inject.view(filterByTag(HealthTags.READY_CHECK)) private readyChecks: ContextView<ReadyCheck>, ) { const startup = once( this.eventEmitter, 'startup', ) as unknown as Promise<void>; const startupCheck = new StartupCheck('startup', () => startup); this.startupCheck = this.healthChecker.registerStartupCheck(startupCheck); const shutdown = once(this.eventEmitter, 'shutdown'); this.shutdownCheck = new ShutdownCheck('shutdown', () => shutdown); } async start() { this.healthChecker.registerShutdownCheck(this.shutdownCheck); const liveChecks = await this.liveChecks.values(); const liveCheckBindings = this.liveChecks.bindings; let index = 0; for (const lc of liveChecks) { const name = liveCheckBindings[index].key; const check = new LivenessCheck(name, lc); this.healthChecker.registerLivenessCheck(check); index++; } const readyChecks = await this.readyChecks.values(); const readyCheckBindings = this.readyChecks.bindings; index = 0; for (const rc of readyChecks) { const name = readyCheckBindings[index].key; const check = new ReadinessCheck(name, rc); this.healthChecker.registerReadinessCheck(check); index++; } this.eventEmitter.emit('startup'); await this.startupCheck; } stop() { this.eventEmitter.emit('shutdown'); // Fix a potential memory leak caused by // https://github.com/CloudNativeJS/cloud-health/blob/2.1.2/src/healthcheck/HealthChecker.ts#L118 // eslint-disable-next-line @typescript-eslint/no-explicit-any const onShutdownRequest = (this.healthChecker as any).onShutdownRequest; if (onShutdownRequest != null) { // Remove the listener from the current process process.removeListener('SIGTERM', onShutdownRequest); } } } function once(emitter: EventEmitter, event: string | symbol): Promise<void> { return onceGeneric(emitter, event) as unknown as Promise<void>; }