Health checks¶
Spindle.Health.routes adds the two routes an orchestrator or a load
balancer probes:
GET /livezruns no check: it answersokwhile the process can answer at all. A database outage should not get every instance restarted.GET /readyzruns every check, side by side, and answersok, or503 not_readynaming the checks that failed. Point a platform that probes only one path here.
Pool.check borrows a connection and runs select 1. A pool whose
connections are all busy passes without waiting; a closed one fails.
Custom checks¶
A check is Spindle.Health.check name f, where f () answers Ok () or
Error why. Return Error, never raise: a check that raises is a bug, and
is answered 500, not 503 not_ready. This server is taken out of service while a file named
maintenance exists:
(* The probes: /livez answers for as long as the process can, and /readyz
only while every check passes. The check here is the application's own:
a file named [maintenance] takes the server out of service, so a load
balancer sends it nobody until the file is gone.
curl -i localhost:8080/readyz 200
touch maintenance
curl -i localhost:8080/readyz 503 not_ready
curl -i localhost:8080/livez 200 all along *)
let hello = Ok "Hello."
let routes =
[
Spindle.get Spindle.Path.root Spindle.Returns.text
(Spindle.Dep.return hello);
]
let in_service =
Spindle.Health.check "maintenance" (fun () ->
if Sys.file_exists "maintenance" then
Error "the maintenance file is there"
else Ok ())
let () =
Spindle.Log.setup ();
Eio_main.run @@ fun env ->
Spindle.serve env (routes @ Spindle.Health.routes [ in_service ])
HTTP/1.1 503 Service Unavailable
content-type: application/json
...
{"error":"not_ready","message":"Not ready: maintenance."}
The answer names only the check; why goes to the log, as a warn line:
not ready: maintenance: the maintenance file is there.
Good to know:
- The framework sets no timeout on a check. A check that waits on something bounds its own wait (the pool has its borrow wait and statement timeout), and the prober sets how long it waits.
- A stopping server refuses new connections, so probes fail without any check.
- Probes are logged at
debug, since something asks every few seconds. ~liveand~readymove the routes to other paths:Spindle.Health.routes ~live:Spindle.Path.(s "healthz") checks.