Files
unified-media-manager/internal/api/health.go
2026-04-24 10:45:19 -07:00

78 lines
2.0 KiB
Go

package api
import (
"context"
"fmt"
"log/slog"
"net/http"
"time"
"github.com/TopherMayor/unified-media-manager/internal/config"
"github.com/TopherMayor/unified-media-manager/internal/db"
"github.com/labstack/echo/v4"
)
func healthLive(c echo.Context) error {
return c.JSON(http.StatusOK, map[string]string{"status": "alive"})
}
func healthReady(database *db.DB, cfg *config.Config) echo.HandlerFunc {
return func(c echo.Context) error {
ctx, cancel := context.WithTimeout(c.Request().Context(), 5*time.Second)
defer cancel()
checks := map[string]string{}
allReady := true
if err := database.Ping(ctx); err != nil {
checks["database"] = "unhealthy: " + err.Error()
allReady = false
slog.Error("readiness check failed", "component", "database", "error", err)
} else {
checks["database"] = "healthy"
}
if err := checkHTTPService(ctx, cfg.QdrantURL+"/healthz"); err != nil {
checks["qdrant"] = "unhealthy: " + err.Error()
allReady = false
slog.Error("readiness check failed", "component", "qdrant", "error", err)
} else {
checks["qdrant"] = "healthy"
}
if err := checkHTTPService(ctx, cfg.OllamaURL+"/api/version"); err != nil {
checks["ollama"] = "unhealthy: " + err.Error()
allReady = false
slog.Error("readiness check failed", "component", "ollama", "error", err)
} else {
checks["ollama"] = "healthy"
}
status := "healthy"
code := http.StatusOK
if !allReady {
status = "degraded"
code = http.StatusServiceUnavailable
}
return c.JSON(code, map[string]interface{}{"status": status, "checks": checks})
}
}
func checkHTTPService(ctx context.Context, url string) error {
client := &http.Client{Timeout: 3 * time.Second}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return fmt.Errorf("build request: %w", err)
}
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("request failed: %w", err)
}
resp.Body.Close()
if resp.StatusCode >= 500 {
return fmt.Errorf("server returned %d", resp.StatusCode)
}
return nil
}