Files
junhong_cmp_fiber/internal/handler/health.go
huang 4507de577b 代码质量改进:修复架构违规、完善文档注释和清理冗余代码
- 修复 health.go handler 直接操作响应的架构违规问题
- 为 model 字段添加 GORM comment 标签(account_role、base、role_permission)
- 为 handler、service、store 包添加包级文档注释
- 清理 customer service 和 personal_customer handler 中注释掉的代码

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-12 16:28:48 +08:00

121 lines
3.1 KiB
Go

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),
})
}