Files
InfiniteAPI/src/Utils/health-status.ts
T
Claude d132e1cfd8 fix: address code review feedback (batch 2)
1. Add logger to writeCacheFile (version-cache.ts)
   - Now logs warnings when file write fails
   - Helps debugging in production environments

2. Sanitize logging in parseGroupResult (communities.ts)
   - Changed from info to debug level
   - Removed full node/groupNode dumps (sensitive data)
   - Now only logs nodeTag and groupId

3. Add input validation in parseNewsletterCreateResponse (newsletter.ts)
   - Validates response structure before destructuring
   - Adds fallback values for parseInt (prevents NaN)
   - Adds null checks for optional fields

4. Add health-status.ts module
   - getHealthStatus(): Full health check with circuit breakers, cache, memory
   - isHealthy(): Simple boolean for liveness probes
   - getSimpleHealthStatus(): Returns 'ok', 'degraded', or 'error'
   - Useful for k8s probes and monitoring dashboards
2026-01-24 20:04:53 +00:00

210 lines
4.7 KiB
TypeScript

/**
* Health Status Utilities
*
* Provides health check and status information for monitoring and k8s probes.
*
* @module Utils/health-status
*/
import { getVersionCacheStatus } from './version-cache.js'
import { globalCircuitRegistry } from './circuit-breaker.js'
/**
* Circuit breaker health information
*/
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. Check circuit breakers
const circuitBreakers: CircuitBreakerHealth[] = []
let openCircuits = 0
for (const [name, breaker] of globalCircuitRegistry.getAll()) {
const stats = breaker.getStats()
const state = breaker.getState()
circuitBreakers.push({
name,
state,
failures: stats.totalFailures,
successes: stats.totalSuccesses,
totalCalls: stats.totalCalls
})
if (state === 'open') {
openCircuits++
}
}
if (openCircuits > 0) {
checks.push({
name: 'circuit_breakers',
status: openCircuits > 2 ? 'fail' : 'warn',
message: `${openCircuits} circuit breaker(s) are open`
})
if (openCircuits > 2) {
overallStatus = 'unhealthy'
} else if (overallStatus === 'healthy') {
overallStatus = 'degraded'
}
} else {
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'
}
}