Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | import { Injectable, Logger } from '@nestjs/common'; export interface ComponentHealth { component: string; status: 'healthy' | 'degraded' | 'unhealthy'; message?: string; latencyMs?: number; checkedAt: string; } @Injectable() export class HealthService { private readonly logger = new Logger(HealthService.name); private readonly checks = new Map<string, () => Promise<ComponentHealth>>(); /** * Register a named health check function. */ registerCheck( component: string, checkFn: () => Promise<ComponentHealth>, ): void { this.checks.set(component, checkFn); } async getLiveness(): Promise<{ status: 'ok'; uptime: number }> { return { status: 'ok', uptime: process.uptime() }; } async getReadiness(): Promise<{ status: string; components: ComponentHealth[]; }> { const results: ComponentHealth[] = []; for (const [component, checkFn] of this.checks.entries()) { try { const result = await checkFn(); results.push(result); } catch (err) { results.push({ component, status: 'unhealthy', message: err.message, checkedAt: new Date().toISOString(), }); } } const overallStatus = results.every((r) => r.status === 'healthy') ? 'ready' : 'degraded'; return { status: overallStatus, components: results }; } async getSummary(): Promise<Record<string, ComponentHealth>> { const summary: Record<string, ComponentHealth> = {}; for (const [component, checkFn] of this.checks.entries()) { try { summary[component] = await checkFn(); } catch (err) { summary[component] = { component, status: 'unhealthy', message: err.message, checkedAt: new Date().toISOString(), }; } } return summary; } } |