Files
Amir ZarrinkafshandJames Elliott 2c6420c47a feat(server): add a verbose health check endpoint (#13127)
`/api/health` answers `200` whenever the server is accepting requests,
which proves the process is alive and nothing else. An instance whose
database or authentication backend has gone away still answers it, so a
load balancer keeps routing logins to a node that cannot serve them.

This adds `/api/health/verbose`, which probes each configured provider
and answers `200` when they all pass or `503` when any of them fails.
`/api/health` is untouched: existing container health checks depend on
it and it is the right answer for a liveness probe, whereas this is a
readiness probe. The endpoint is disabled unless
`server.endpoints.health.verbose` is enabled.

The probes are the ones the startup checks already run.
`Providers.HealthChecks` walks the named providers through the same
`model.StartupCheck` interface `StartupChecks` uses and returns a result
each, so a failing provider does not stop the rest being probed. The
provider names move from `internal/middlewares` to
`internal/configuration/schema` so the configuration layer can validate
against them, and `middlewares` keeps its existing names as aliases.

A provider error carries connection strings, host names and directory
base DNs, and this endpoint is unauthenticated, so by default a failure
is reported only as `"status": "error"` and the message goes to the log.
`server.endpoints.health.detailed` includes it in the response for the
duration of an investigation, and the option documents what it
discloses.

`server.endpoints.health.providers` defaults to `storage`, `session` and
`user`, the three on the authentication request path. Probing
`notification` opens an SMTP connection and probing `ntp` contacts an
external server, so neither is included unless asked for.
`server.endpoints.health.cache` reuses a result for ten seconds by
default so that a readiness probe polling every second does not open a
connection to every provider every second, and the response reports
whether it was served from that cache. The endpoint also has its own
rate limiter rather than borrowing another bucket.

Fixes #10357.

---------

Signed-off-by: Amir Zarrinkafsh <3339418+nightah@users.noreply.github.com>
Signed-off-by: James Elliott <james-d-elliott@users.noreply.github.com>
Co-authored-by: James Elliott <james-d-elliott@users.noreply.github.com>
2026-09-20 11:40:19 +00:00
..