package handler import ( "context" "time" "github.com/gofiber/fiber/v2" "github.com/redis/go-redis/v9" "go.uber.org/zap" "gorm.io/gorm" "github.com/break/junhong_cmp_fiber/pkg/response" ) // HealthHandler 健康检查处理器 type HealthHandler struct { db *gorm.DB redis *redis.Client logger *zap.Logger } // NewHealthHandler 创建健康检查处理器实例 func NewHealthHandler(db *gorm.DB, redis *redis.Client, logger *zap.Logger) *HealthHandler { return &HealthHandler{ db: db, redis: redis, logger: logger, } } // Check 健康检查 // GET /health func (h *HealthHandler) Check(c *fiber.Ctx) error { ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() healthStatus := fiber.Map{ "status": "healthy", "timestamp": time.Now().Format(time.RFC3339), "services": fiber.Map{}, } services := healthStatus["services"].(fiber.Map) allHealthy := true // 检查 PostgreSQL sqlDB, err := h.db.DB() if err != nil { h.logger.Error("获取 PostgreSQL DB 实例失败", zap.Error(err)) services["postgres"] = fiber.Map{ "status": "down", "error": err.Error(), } allHealthy = false } else { if err := sqlDB.PingContext(ctx); err != nil { h.logger.Error("PostgreSQL Ping 失败", zap.Error(err)) services["postgres"] = fiber.Map{ "status": "down", "error": err.Error(), } allHealthy = false } else { // 获取连接池统计信息 stats := sqlDB.Stats() services["postgres"] = fiber.Map{ "status": "up", "open_conns": stats.OpenConnections, "in_use": stats.InUse, "idle": stats.Idle, "wait_count": stats.WaitCount, "wait_duration": stats.WaitDuration.String(), "max_idle_close": stats.MaxIdleClosed, "max_lifetime_close": stats.MaxLifetimeClosed, } } } // 检查 Redis if err := h.redis.Ping(ctx).Err(); err != nil { h.logger.Error("Redis Ping 失败", zap.Error(err)) services["redis"] = fiber.Map{ "status": "down", "error": err.Error(), } allHealthy = false } else { // 获取 Redis 信息 poolStats := h.redis.PoolStats() services["redis"] = fiber.Map{ "status": "up", "hits": poolStats.Hits, "misses": poolStats.Misses, "timeouts": poolStats.Timeouts, "total_conns": poolStats.TotalConns, "idle_conns": poolStats.IdleConns, "stale_conns": poolStats.StaleConns, } } // 设置总体状态 if !allHealthy { healthStatus["status"] = "degraded" h.logger.Warn("健康检查失败: 部分服务不可用") } else { h.logger.Info("健康检查成功: 所有服务正常") } // 统一使用 response.Success 返回,状态信息在 data.status 中标记 // 健康检查端点本身能响应即视为成功,具体服务状态由 data.status 字段表示 return response.Success(c, healthStatus) } // HealthCheck 简单健康检查(保持向后兼容) func HealthCheck(c *fiber.Ctx) error { return response.Success(c, fiber.Map{ "status": "healthy", "timestamp": time.Now().Format(time.RFC3339), }) }