/** * Health Status Utilities * * Provides health check and status information for monitoring and k8s probes. * * @module Utils/health-status */ import { getVersionCacheStatus } from './version-cache.js' /** * Circuit breaker health information (kept for k8s probe schema stability — * always reports an empty list now that circuit breakers were removed in * favour of bounded-retry). */ export interface CircuitBreakerHealth { name: string state: 'closed' | 'open' | 'half-open' failures: number successes: number totalCalls: number } /** * Cache health information */ export interface CacheHealth { versionCache: { hasCache: boolean isExpired: boolean ageMs: number | null source: string | null } } /** * Overall health status */ export interface HealthStatus { status: 'healthy' | 'degraded' | 'unhealthy' timestamp: number uptime: number version: string circuitBreakers: CircuitBreakerHealth[] cache: CacheHealth checks: { name: string status: 'pass' | 'warn' | 'fail' message?: string }[] } /** * Get the current health status of the Baileys instance. * * Useful for: * - Kubernetes liveness/readiness probes * - Load balancer health checks * - Monitoring dashboards * * @returns HealthStatus object with detailed status information * * @example * ```typescript * import { getHealthStatus } from '@whiskeysockets/baileys' * * // Simple health check endpoint * app.get('/health', (req, res) => { * const health = getHealthStatus() * const statusCode = health.status === 'healthy' ? 200 : * health.status === 'degraded' ? 200 : 503 * res.status(statusCode).json(health) * }) * * // Kubernetes probe * app.get('/healthz', (req, res) => { * const health = getHealthStatus() * res.status(health.status !== 'unhealthy' ? 200 : 503).send(health.status) * }) * ``` */ export function getHealthStatus(): HealthStatus { const checks: HealthStatus['checks'] = [] let overallStatus: HealthStatus['status'] = 'healthy' // 1. Check version cache const versionCacheStatus = getVersionCacheStatus() if (!versionCacheStatus.hasCache) { checks.push({ name: 'version_cache', status: 'warn', message: 'No version cache available' }) if (overallStatus === 'healthy') overallStatus = 'degraded' } else if (versionCacheStatus.isExpired) { checks.push({ name: 'version_cache', status: 'warn', message: 'Version cache is expired' }) if (overallStatus === 'healthy') overallStatus = 'degraded' } else { checks.push({ name: 'version_cache', status: 'pass' }) } // 2. Circuit breakers were removed in favour of bounded-retry. // Keep the field for backward-compat with k8s probe schema, always empty. const circuitBreakers: CircuitBreakerHealth[] = [] checks.push({ name: 'circuit_breakers', status: 'pass' }) // 3. Check memory usage (warn if > 90%) const memUsage = process.memoryUsage() const heapUsedPercent = (memUsage.heapUsed / memUsage.heapTotal) * 100 if (heapUsedPercent > 90) { checks.push({ name: 'memory', status: 'warn', message: `Heap usage is ${heapUsedPercent.toFixed(1)}%` }) if (overallStatus === 'healthy') overallStatus = 'degraded' } else { checks.push({ name: 'memory', status: 'pass' }) } return { status: overallStatus, timestamp: Date.now(), uptime: process.uptime(), version: process.env.npm_package_version || 'unknown', circuitBreakers, cache: { versionCache: { hasCache: versionCacheStatus.hasCache, isExpired: versionCacheStatus.isExpired, ageMs: versionCacheStatus.age, source: versionCacheStatus.source } }, checks } } /** * Simple health check - returns true if system is healthy or degraded. * Use this for basic liveness probes. * * @returns true if healthy or degraded, false if unhealthy */ export function isHealthy(): boolean { const status = getHealthStatus() return status.status !== 'unhealthy' } /** * Get a simple status string for minimal health endpoints. * * @returns 'ok', 'degraded', or 'error' */ export function getSimpleHealthStatus(): 'ok' | 'degraded' | 'error' { const status = getHealthStatus() switch (status.status) { case 'healthy': return 'ok' case 'degraded': return 'degraded' case 'unhealthy': return 'error' } }