feat: 系统优化 - ESLint、Tailwind、前端健壮性、后端工程化、运维可观测性
- 前端: ESLint+Prettier配置、Tailwind v4配置、ErrorBoundary、全局AuthLoader优化、ReactQuery分层 - 后端: MinIO凭证移除、Docker统一为govai品牌、zerolog日志封装、错误码枚举、文件上传校验、单元测试(13项全通过) - 运维: 健康检查增强(PG/Redis ping)、Prometheus指标(/metrics端点)、多租户tenant包、RateLimit nil防御 - 移动: citation_prompt.txt → internal/assets/
This commit is contained in:
@@ -6,15 +6,80 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/enterprise-ai-platform/server/internal/response"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
var startTime = time.Now()
|
||||
type HealthHandler struct {
|
||||
pool *pgxpool.Pool
|
||||
rdb *redis.Client
|
||||
}
|
||||
|
||||
func HealthCheck(w http.ResponseWriter, r *http.Request) {
|
||||
response.JSON(w, http.StatusOK, map[string]any{
|
||||
"status": "ok",
|
||||
"service": "aily-portal-api",
|
||||
func NewHealthHandler(pool *pgxpool.Pool, rdb *redis.Client) *HealthHandler {
|
||||
return &HealthHandler{pool: pool, rdb: rdb}
|
||||
}
|
||||
|
||||
func (h *HealthHandler) HealthCheck(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
type dep struct {
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
deps := []dep{}
|
||||
|
||||
// PostgreSQL
|
||||
if h.pool != nil {
|
||||
if err := h.pool.Ping(ctx); err != nil {
|
||||
deps = append(deps, dep{Name: "postgres", Status: "down", Error: err.Error()})
|
||||
} else {
|
||||
deps = append(deps, dep{Name: "postgres", Status: "up"})
|
||||
}
|
||||
} else {
|
||||
deps = append(deps, dep{Name: "postgres", Status: "not_configured"})
|
||||
}
|
||||
|
||||
// Redis
|
||||
if h.rdb != nil {
|
||||
if err := h.rdb.Ping(ctx).Err(); err != nil {
|
||||
deps = append(deps, dep{Name: "redis", Status: "down", Error: err.Error()})
|
||||
} else {
|
||||
deps = append(deps, dep{Name: "redis", Status: "up"})
|
||||
}
|
||||
} else {
|
||||
deps = append(deps, dep{Name: "redis", Status: "not_configured"})
|
||||
}
|
||||
|
||||
// Overall status
|
||||
status := "ok"
|
||||
httpStatus := http.StatusOK
|
||||
for _, d := range deps {
|
||||
if d.Status == "down" {
|
||||
status = "degraded"
|
||||
httpStatus = http.StatusServiceUnavailable
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Runtime stats
|
||||
var m runtime.MemStats
|
||||
runtime.ReadMemStats(&m)
|
||||
|
||||
response.JSON(w, httpStatus, map[string]any{
|
||||
"status": status,
|
||||
"service": "govai-portal-api",
|
||||
"uptime": time.Since(startTime).String(),
|
||||
"go": runtime.Version(),
|
||||
"memory": map[string]any{
|
||||
" Alloc": m.Alloc / 1024 / 1024,
|
||||
"Sys": m.Sys / 1024 / 1024,
|
||||
"NumGC": m.NumGC,
|
||||
"Goroutine": runtime.NumGoroutine(),
|
||||
},
|
||||
"dependencies": deps,
|
||||
})
|
||||
}
|
||||
|
||||
// startTime is shared with the original health.go init block.
|
||||
var startTime = time.Now()
|
||||
Reference in New Issue
Block a user