Distinguish liveness from readiness in an application health check

A process that answers HTTP requests may still be unable to serve useful work. If its database is unavailable, a request to a trivial route can succeed while an order lookup fails. Give process health and dependency readiness distinct meanings so that an outage produces the intended operational response.
Write down the two decisions
In this illustrative policy, liveness asks whether the application process can execute a minimal handler. Readiness asks whether a required database operation succeeds within a short budget. The names do not implement the policy; the handler and the infrastructure consuming it must agree.
def health_reply(process_ok, database_ok):
live = 200 if process_ok else 503
ready = 200 if process_ok and database_ok else 503
return live, ready
assert health_reply(True, False) == (200, 503)
assert health_reply(True, True) == (200, 200)
This small decision function is a synthetic fixture. It performs no network request and says nothing about the current state of a deployed application. Its assertions check the policy's expected status pairs.
Liveness follows process response; readiness also depends on the required database check.
Inject a dependency failure
During a local exercise, make the database check fail while leaving the process responsive. Observe the readiness result and ordinary request errors. If the platform routes new requests away from an unready instance, confirm that behavior with requests through the actual routing layer.
Docker Compose can use a healthcheck to decide when a dependent service starts. Its documented startup condition is useful here, but it does not provide the entire traffic-routing and recovery policy of every hosting platform. Read the consumer of the health result before assuming what an unhealthy status will trigger.
Avoid turning an outage into a restart storm
A shared database failure usually affects every application instance. Restarting all of them repeatedly can add connection attempts while losing useful diagnostic context. Choose restart rules based on failures that a restart can plausibly repair. Give dependency checks a timeout so that the readiness handler does not consume an unbounded number of workers.
Keep responses small and avoid exposing connection strings or internal error details. A readiness query also needs a defined scope: a basic connection test does not prove that every table, migration or external service is ready. If an optional reporting service is down, decide whether ordinary application traffic should remain available.
Reference: Compose startup conditions. The engineering blog has further application failure examples.