Vellum/internal/httpapi/health.go
mithral eb1ad6d920 Phase 0: skeleton, config, migrations, health check, container
Bootstraps Vellum as a single Go binary with one SQLite database.

- core: env-driven config, slog logging, SQLite (WAL) with pooled pragmas,
  embedded migration runner keyed on PRAGMA user_version
- migrations/0001_core.sql: identity, media, user state, infra. Media items
  are global; all per-user state (progress, favorites, grants) is a join.
  One polymorphic progress table covers every media kind.
- httpapi: request-ID, structured request logging, panic recovery, JSON
  endpoints for /healthz and /api/v1/version
- multi-arch Dockerfile (pure-Go SQLite, CGO_ENABLED=0) with an entrypoint
  that honours PUID/PGID like the rest of the self-hosted stack
- tests for migration idempotency, FK enforcement, WAL, config, middleware

Media does not exist yet. Nothing is exposed beyond health and version.
2026-10-09 16:26:08 -04:00

45 lines
1.1 KiB
Go

package httpapi
import (
"context"
"net/http"
"time"
)
// handleHealth reports process liveness and database reachability.
//
// Returns 503 when the database cannot be pinged, so a container orchestrator
// restarts a wedged process instead of routing traffic to it.
func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 2*time.Second)
defer cancel()
dbStatus := "ok"
code := http.StatusOK
if err := s.db.PingContext(ctx); err != nil {
dbStatus = "unreachable"
code = http.StatusServiceUnavailable
s.log.Error("health check: database unreachable", "err", err)
}
status := "ok"
if code != http.StatusOK {
status = "degraded"
}
writeJSON(w, code, map[string]any{
"status": status,
"version": s.version,
"uptime_seconds": int(time.Since(s.started).Seconds()),
"database": dbStatus,
})
}
// handleVersion returns build information.
func (s *Server) handleVersion(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, map[string]any{
"name": "vellum",
"version": s.version,
"api": "v1",
})
}