Some checks failed
CI / Build & Test (push) Failing after 1m31s
- Add user management endpoints (list/create/get/update/delete) with pagination and search - Add dashboard stats endpoint with tenant/user/online counts and growth metrics - Add tenant resolver middleware for multi-tenant request scoping - Add i18n kernel with zh/en message files and AcceptLanguage middleware - Add WebSocket hub/handler for real-time communication - Add job scheduler kernel with cron support - Add plugin sandbox for isolated execution - Add storage kernel (local filesystem) - Add event bus kernel for pub/sub - Add cache kernel abstraction - Add database migration runner and version upgrade checker - Add rate limiting middleware with Redis backend - Add SQL migrations for rbac, audit_logs, settings, notifications, examples - Extend user repository with list/delete/count operations - Register all module routes with tenant resolver
124 lines
2.9 KiB
Go
124 lines
2.9 KiB
Go
package health
|
||
|
||
import (
|
||
"context"
|
||
"net/http"
|
||
"time"
|
||
|
||
"mengstack/internal/app/version"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
"github.com/redis/go-redis/v9"
|
||
"go.uber.org/zap"
|
||
"gorm.io/gorm"
|
||
)
|
||
|
||
type Handler struct {
|
||
db *gorm.DB
|
||
rdb *redis.Client
|
||
log *zap.Logger
|
||
}
|
||
|
||
func NewHandler(db *gorm.DB, rdb *redis.Client, log *zap.Logger) *Handler {
|
||
return &Handler{db: db, rdb: rdb, log: log}
|
||
}
|
||
|
||
// Handle godoc
|
||
// @Summary 健康检查
|
||
// @Description 检查 PostgreSQL 和 Redis 连接状态
|
||
// @Tags System
|
||
// @Produce json
|
||
// @Success 200 {object} object{status=string,database=string,redis=string,timestamp=integer,version=string,trace_id=string}
|
||
// @Router /health [get]
|
||
func (h *Handler) Handle(c *gin.Context) {
|
||
status := "ok"
|
||
dbStatus := "connected"
|
||
redisStatus := "connected"
|
||
|
||
sqlDB, err := h.db.DB()
|
||
if err != nil || sqlDB.Ping() != nil {
|
||
status = "degraded"
|
||
dbStatus = "disconnected"
|
||
}
|
||
|
||
ctx, cancel := context.WithTimeout(c.Request.Context(), 2*time.Second)
|
||
defer cancel()
|
||
if h.rdb.Ping(ctx).Err() != nil {
|
||
status = "degraded"
|
||
redisStatus = "disconnected"
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"status": status,
|
||
"database": dbStatus,
|
||
"redis": redisStatus,
|
||
"timestamp": time.Now().Unix(),
|
||
"version": version.Version,
|
||
"trace_id": c.GetString("trace_id"),
|
||
})
|
||
}
|
||
|
||
// Version godoc
|
||
// @Summary 版本信息
|
||
// @Description 返回构建版本、提交哈希、编译时间等
|
||
// @Tags System
|
||
// @Produce json
|
||
// @Success 200 {object} version.Info
|
||
// @Router /api/version [get]
|
||
func (h *Handler) Version(c *gin.Context) {
|
||
c.JSON(http.StatusOK, version.Current())
|
||
}
|
||
|
||
// Healthz godoc
|
||
// @Summary 存活探针
|
||
// @Description Kubernetes liveness probe,进程存活即返回 200
|
||
// @Tags System
|
||
// @Produce json
|
||
// @Success 200 {object} object{status=string}
|
||
// @Router /healthz [get]
|
||
func (h *Handler) Healthz(c *gin.Context) {
|
||
c.JSON(http.StatusOK, gin.H{"status": "ok"})
|
||
}
|
||
|
||
// Readyz godoc
|
||
// @Summary 就绪探针
|
||
// @Description Kubernetes readiness probe,检查数据库和 Redis 连接
|
||
// @Tags System
|
||
// @Produce json
|
||
// @Success 200 {object} object{status=string,database=string,redis=string}
|
||
// @Failure 503 {object} object{status=string,database=string,redis=string}
|
||
// @Router /readyz [get]
|
||
func (h *Handler) Readyz(c *gin.Context) {
|
||
ctx, cancel := context.WithTimeout(c.Request.Context(), 2*time.Second)
|
||
defer cancel()
|
||
|
||
dbOK := true
|
||
sqlDB, err := h.db.DB()
|
||
if err != nil || sqlDB.Ping() != nil {
|
||
dbOK = false
|
||
}
|
||
|
||
redisOK := true
|
||
if h.rdb.Ping(ctx).Err() != nil {
|
||
redisOK = false
|
||
}
|
||
|
||
body := gin.H{
|
||
"database": boolToStatus(dbOK),
|
||
"redis": boolToStatus(redisOK),
|
||
}
|
||
|
||
if !dbOK || !redisOK {
|
||
c.JSON(http.StatusServiceUnavailable, body)
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, body)
|
||
}
|
||
|
||
func boolToStatus(ok bool) string {
|
||
if ok {
|
||
return "connected"
|
||
}
|
||
return "disconnected"
|
||
}
|