# health HTTP health check handler with parallel checks, timeouts, and two-level criticality. ## Purpose Provides a single `http.Handler` that interrogates any number of `Checkable` infrastructure components concurrently and returns a JSON response with per-component status and an overall service status. Designed to be mounted at `/health` and consumed by load balancers and orchestrators. ## Tier & Dependencies **Tier 1** — depends only on Go stdlib (`context`, `encoding/json`, `net/http`, `time`). No external or internal module imports. ## Key Design Decisions - **Parallel checks** (ADR-001): every registered component is checked in its own goroutine. A `context.WithTimeout(r.Context(), 5*time.Second)` provides the deadline for the entire request. The handler blocks until all goroutines report via a buffered channel. - **Two-level criticality** (ADR-002): `LevelCritical` (value `0`) → `DOWN` + HTTP 503 on failure; `LevelDegraded` (value `1`) → `DEGRADED` + HTTP 200 on failure. The zero-value default is `LevelCritical`. - **`Checkable` interface** (ADR-003): infrastructure components implement `HealthCheck(ctx) error`, `Name() string`, and `Priority() Level`. The health package defines the interface; infra packages satisfy it — not the reverse. - **Duck-typed `Logger`** (global ADR-001): the `Logger` interface is defined locally in this package. Any logger that matches the method set (including `logz.Logger`) is accepted without an import of `logz`. ## Patterns Construct the handler at app bootstrap and pass all `Checkable` components: ```go db := postgres.New(logger, cfg) // satisfies health.Checkable rdb := redis.New(logger, cfg) // satisfies health.Checkable h := health.NewHandler(logger, db, rdb) router.Get("/health", h) ``` Implement `Checkable` on a custom type: ```go type myService struct{} func (s *myService) HealthCheck(ctx context.Context) error { return s.ping(ctx) } func (s *myService) Name() string { return "my-service" } func (s *myService) Priority() health.Level { return health.LevelDegraded } ``` ## What to Avoid - Do not add a global/package-level handler or registry. `NewHandler` is the only constructor; use dependency injection. - Do not call `NewHandler` with nil logger — the handler will panic on the first request when it calls `logger.WithContext`. - Do not import infra modules (postgres, mysql, etc.) from this package. The dependency must flow one way: infra → health. - Do not remove the buffered channel (`make(chan result, len(h.checks))`). Making it unbuffered would leak goroutines if the handler returns before draining all results. ## Testing Notes - `health_test.go` covers: no checks (UP), all UP, critical DOWN (503), degraded DOWN (200), mixed DOWN+DEGRADED (503), parallel execution timing, JSON shape, and context timeout propagation. - `compliance_test.go` contains compile-time interface satisfaction checks for `Logger` and `Checkable`. Run `go build ./...` to verify them without executing any runtime code. - Tests use an in-process `httptest.NewRecorder` — no real network or infrastructure required. - The parallelism test uses a 100 ms delay per check and asserts total elapsed < 300 ms. It is timing-sensitive; extremely slow CI runners may produce false negatives.