- 6 config blocks (DB/Redis/Channel/Refresh/Partition/Extension with 4 EnableXxx=false) - 14 Prometheus metric declarations - self-impl healthz (/healthz + /metrics) — bypasses pkg/health to keep /metrics - main.go startup: logger → config → DB → Redis → healthz HTTP :21009 - 10 SQL migrations: events partitioned + 4 MV + 3 pre-agg + refresh_log + 7-day initial 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
57 lines
1.2 KiB
Go
57 lines
1.2 KiB
Go
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)
|
|
}
|