package handler import ( "net/http" "runtime" "time" "github.com/enterprise-ai-platform/server/internal/response" "github.com/jackc/pgx/v5/pgxpool" "github.com/redis/go-redis/v9" ) type HealthHandler struct { pool *pgxpool.Pool rdb *redis.Client } 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()