package handler import ( "context" "database/sql" "net/http" "time" "github.com/gin-gonic/gin" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/redis/go-redis/v9" ) // Healthz 健康检查 + /metrics 端点 type Healthz struct { db *sql.DB redis *redis.Client } // NewHealthz 构造 healthz handler func NewHealthz(db *sql.DB, rdb *redis.Client) *Healthz { return &Healthz{db: db, redis: rdb} } // Register 在 gin engine 上注册 /healthz 和 /metrics 路由 func (h *Healthz) Register(r *gin.Engine) { r.GET("/healthz", h.handleHealthz) r.GET("/metrics", gin.WrapH(promhttp.Handler())) } func (h *Healthz) handleHealthz(c *gin.Context) { ctx, cancel := context.WithTimeout(c.Request.Context(), 1*time.Second) defer cancel() status := gin.H{"status": "ok"} if err := h.db.PingContext(ctx); err != nil { status["db"] = "down" status["db_error"] = err.Error() } else { status["db"] = "up" } if err := h.redis.Ping(ctx).Err(); err != nil { status["redis"] = "down" status["redis_error"] = err.Error() } else { status["redis"] = "up" } code := http.StatusOK if status["db"] == "down" || status["redis"] == "down" { code = http.StatusServiceUnavailable } c.JSON(code, status) }