Health checks
The server exposes two independent probes. Use both: they answer different questions, and treating them as one causes an orchestrator either to kill a healthy instance or to send traffic to one that cannot serve it yet.
| Endpoint | Question it answers | Use it for |
|---|---|---|
/health/live | Is the process up and serving HTTP? | Liveness probe — restart the container when this fails |
/health/ready | Has startup work finished and is PostgreSQL reachable, so FHIR traffic can be served? | Readiness probe — add or remove the instance from the load balancer |
Both are outside the FHIR base path, so they need no FHIR content type and are unaffected by tenancy.
Liveness
curl -i http://localhost:9090/health/live
HTTP/1.1 200 OK
Content-Length: 0
It returns 200 as soon as the HTTP listener is accepting connections. The response has no body.
Readiness
curl -i http://localhost:9090/health/ready
HTTP/1.1 200 OK
Content-Length: 0
Readiness turns 200 only once startup work has completed — including
Implementation Guide package loading, which runs in the
background — and PostgreSQL is reachable. On a deployment that loads large packages, expect a
window where liveness already returns 200 while readiness is still 503. That is the intended
behaviour: the process is alive but must not receive traffic yet.
Each call pings PostgreSQL with a 2-second timeout and uses the result directly, so an unreachable database drops the instance from the load balancer on the next probe and recovery is visible just as quickly. Readiness does not probe the terminology server; monitor that separately — see Observability.
Wiring probes in Kubernetes
livenessProbe:
httpGet:
path: /health/live
port: 9090
periodSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /health/ready
port: 9090
periodSeconds: 5
failureThreshold: 2
Give readiness a startup allowance long enough to cover IG loading, either with a generous
failureThreshold or a startupProbe against /health/ready.
The container image is distroless and has no shell or wget, so a CMD-SHELL-style Docker
healthcheck inside the container will not work. Probe it externally — from the orchestrator, or from
the host with curl -fsS http://localhost:9090/health/ready.