Health Check
The Health Check pattern exposes liveness, readiness, and startup endpoints so orchestrators and load balancers route traffic only to healthy instances and restart broken ones. Probe scope must be chosen carefully to avoid restart storms and correlated failures.
An orchestrator or load balancer needs a reliable way to know whether a service instance can handle traffic. The Health Check pattern provides it: the service exposes endpoints (commonly HTTP, but also gRPC or TCP) that report its status. Infrastructure polls these endpoints and routes traffic only to instances that pass, restarting or replacing those that fail.
How It Works
Mature systems distinguish several probe types, a separation formalized by Kubernetes:
- Liveness: "is the process alive and not deadlocked?" Failing it triggers a restart. It should be cheap and avoid checking dependencies, or a downstream outage causes a restart loop.
- Readiness: "can it serve requests right now?" Failing it removes the instance from the load-balancer pool without killing it — useful during startup, warm-up, or temporary dependency loss.
- Startup: "has a slow-starting app finished initializing?" It gates the other probes so they do not fire prematurely.
A health endpoint may run shallow checks (process responds) or deep checks (database reachable, queue connected, disk writable). Deep checks give richer signal but can cascade failures if a shared dependency makes every instance report unhealthy at once.
When to Use It
Health checks are mandatory in any orchestrated or load-balanced environment: Kubernetes, ECS, Nomad, cloud load balancers, and service meshes all consume them. Use liveness for crash/deadlock recovery, readiness to gate traffic during startup and transient dependency loss, and startup probes for slow-booting apps. This pattern is a routine and important part of containerizing services (for example, migrations such as docker-compose-to-kubernetes or vm-to-kubernetes).
Trade-offs
Liveness probes that test dependencies cause restart storms when a shared dependency fails — a common, damaging misconfiguration. Deep checks risk correlated failures; shallow checks may report "healthy" while the service is functionally broken. Probe intervals and thresholds must balance fast detection against flapping. Health endpoints can also leak internal detail and should be access-controlled when they expose dependency status.
Related Patterns
Health checks overlap with heartbeat-pattern (push vs. pull liveness), feed watchdog and auto-healing controllers, inform circuit-breaker decisions, and are frequently implemented or aggregated via the sidecar-pattern.
Example
Kubernetes probes:
livenessProbe: httpGet { path: /healthz, port: 8080 } # restart if fails
readinessProbe: httpGet { path: /ready, port: 8080 } # depool if fails
/healthz returns 200 if the process is responsive; /ready returns 200 only when the database and cache connections are established.