/** * @file 健康检查服务 * @author hotok * @date 2025-06-28 * @lastEditor hotok * @lastEditTime 2025-06-28 * @description 系统健康状态检查业务逻辑,包括数据库、Redis等依赖检查 */ import type { Context } from 'elysia'; import { Redis } from '@/utils/redis'; import { pool } from '@/utils/mysql'; import { Logger } from '@/plugins/logger/logger.service'; // 临时内联类型定义 interface ComponentStatus { status: 'healthy' | 'unhealthy' | 'degraded'; responseTime?: number; error?: string; details?: Record; } interface HealthStatus { code: number; message: string; data: { status: 'healthy' | 'unhealthy' | 'degraded'; timestamp: string; uptime: number; responseTime: number; version: string; environment: string; error?: string; components: { mysql?: ComponentStatus; redis?: ComponentStatus; [key: string]: ComponentStatus | undefined; }; }; } interface DetailedHealthStatus extends HealthStatus { data: HealthStatus['data'] & { system?: { platform: string; arch: string; nodeVersion: string; runtime: string; pid: number; cwd: string; }; performance?: { cpuUsage: { user: number; system: number; }; memoryUsage: { rss: number; heapTotal: number; heapUsed: number; external: number; arrayBuffers: number; }; uptime: number; }; }; } /** * 健康检查服务类 * 提供系统及依赖服务的健康状态检查 */ class HealthService { /** * Redis实例 */ private redis: Redis; constructor() { this.redis = new Redis(); } /** * 获取基本健康状态 * @param ctx Elysia上下文 * @returns 健康状态信息 */ async getHealthStatus(ctx: Context): Promise { const startTime = Date.now(); const timestamp = new Date().toISOString(); try { // 并行检查所有依赖 const [mysqlStatus, redisStatus] = await Promise.allSettled([ this.checkMysqlHealth(), this.checkRedisHealth(), ]); /** 系统整体状态 */ const overallStatus = this.determineOverallStatus([ mysqlStatus.status === 'fulfilled' ? mysqlStatus.value : { status: 'unhealthy', error: 'Connection failed' }, redisStatus.status === 'fulfilled' ? redisStatus.value : { status: 'unhealthy', error: 'Connection failed' }, ]); const responseTime = Date.now() - startTime; return { code: overallStatus === 'healthy' ? 0 : 1, message: overallStatus === 'healthy' ? '所有服务运行正常' : '部分服务异常', data: { status: overallStatus, timestamp, uptime: process.uptime(), responseTime, version: process.env.npm_package_version || '1.0.0', environment: process.env.NODE_ENV || 'development', components: { mysql: mysqlStatus.status === 'fulfilled' ? mysqlStatus.value : { status: 'unhealthy', error: 'Connection failed' }, redis: redisStatus.status === 'fulfilled' ? redisStatus.value : { status: 'unhealthy', error: 'Connection failed' }, }, }, }; } catch (error) { Logger.error(error as Error); return { code: 1, message: '健康检查异常', data: { status: 'unhealthy', timestamp, uptime: process.uptime(), responseTime: Date.now() - startTime, version: process.env.npm_package_version || '1.0.0', environment: process.env.NODE_ENV || 'development', error: 'Health check failed', components: {}, }, }; } } /** * 获取详细健康状态 * @param ctx Elysia上下文 * @returns 详细健康状态信息 */ async getDetailedHealthStatus(ctx: Context): Promise { const startTime = Date.now(); const timestamp = new Date().toISOString(); try { // 获取基本健康状态 const basicHealth = await this.getHealthStatus(ctx); // 获取系统资源信息 const systemInfo = this.getSystemInfo(); return { ...basicHealth, data: { ...basicHealth.data, system: systemInfo, performance: { cpuUsage: process.cpuUsage(), memoryUsage: process.memoryUsage(), uptime: process.uptime(), }, }, }; } catch (error) { Logger.error(error as Error); return { code: 1, message: '详细健康检查异常', data: { status: 'unhealthy', timestamp, uptime: process.uptime(), responseTime: Date.now() - startTime, version: process.env.npm_package_version || '1.0.0', environment: process.env.NODE_ENV || 'development', error: 'Detailed health check failed', components: {}, }, }; } } /** * 检查MySQL健康状态 * @returns MySQL组件状态 */ private async checkMysqlHealth(): Promise { try { const startTime = Date.now(); await pool.execute('SELECT 1'); const responseTime = Date.now() - startTime; return { status: 'healthy', responseTime, details: { connection: 'active', host: process.env.DB_HOST || 'localhost', port: process.env.DB_PORT || '3306', }, }; } catch (error) { Logger.error(error as Error); return { status: 'unhealthy', error: (error as Error).message, details: { connection: 'failed', host: process.env.DB_HOST || 'localhost', port: process.env.DB_PORT || '3306', }, }; } } /** * 检查Redis健康状态 * @returns Redis组件状态 */ private async checkRedisHealth(): Promise { try { const startTime = Date.now(); const isHealthy = await this.redis.checkRedisHealth(); const responseTime = Date.now() - startTime; if (isHealthy) { const redisStatus = this.redis.getRedisStatus(); return { status: 'healthy', responseTime, details: { connection: 'active', ...redisStatus.config, }, }; } else { return { status: 'unhealthy', error: 'Redis ping failed', details: { connection: 'failed', }, }; } } catch (error) { Logger.error(error as Error); return { status: 'unhealthy', error: (error as Error).message, details: { connection: 'failed', }, }; } } /** * 确定整体状态 * @param components 各组件状态 * @returns 整体状态 */ private determineOverallStatus(components: ComponentStatus[]): 'healthy' | 'unhealthy' | 'degraded' { const healthyCount = components.filter(c => c.status === 'healthy').length; const totalCount = components.length; if (healthyCount === totalCount) { return 'healthy'; } else if (healthyCount === 0) { return 'unhealthy'; } else { return 'degraded'; } } /** * 获取系统信息 * @returns 系统信息 */ private getSystemInfo() { return { platform: process.platform, arch: process.arch, nodeVersion: process.version, runtime: 'Bun', pid: process.pid, cwd: process.cwd(), }; } } /** * 导出健康检查服务实例 */ export const healthService = new HealthService();