Bastion.Health
lib/health.march — Bastion.Health: built-in health check endpoint.
Serves GET /health → 200 {"status":"ok"} in normal operation. During a drain (SIGTERM received), returns 503 {"status":"draining"}.
The drain state is stored in a Vault table so it can be toggled without restarting the process. Call Bastion.Health.start_drain() from a signal handler to transition to the draining state.
── Usage ──────────────────────────────────────────────────────────────────────
-- In your endpoint pipeline (before the router):
let c = Bastion.Health.plug(conn)
-- Register custom checks:
let checks = [
Bastion.Health.check("depot", fn () ->
match Pool.with_conn(my_pool, fn c -> Connection.simple_query(c, "SELECT 1") end) do
Ok(_) -> Ok(())
Err(e) -> Err(e)
end
end),
Bastion.Health.check("vault", fn () ->
if Vault.has(my_table, "heartbeat") do Ok(()) else Err("missing heartbeat key") end
end)
]
let c = Bastion.Health.plug_with_checks(conn, checks)Types
Functions
Build a named health check from a probe function.
Bastion.Health.check("depot", fn () ->
match Pool.with_conn(my_pool, fn c -> Connection.simple_query(c, "SELECT 1") end) do
Ok(_) -> Ok(())
Err(e) -> Err(e)
end
end)Returns true when a drain is in progress (start_drain was called).
Plug that serves GET /health.
Returns 200 {"status":"ok"} normally, or 503 {"status":"draining"} when
start_drain() has been called. Passes all other paths through.Plug that serves GET /health with custom probe functions.
Each check's probe is called. If all pass and the server is not draining,
returns 200. If any check fails, returns 503 {"status":"unhealthy"}. If
draining, returns 503 {"status":"draining"} (checks are skipped).Signal that a drain is beginning. The health endpoint will return 503 {"status":"draining"} until the process exits.
Call this in a SIGTERM handler to give load balancers time to stop routing
before the drain timeout fires.