Compose applications
Add health and startup handling
Distinguish process startup from service readiness and make the API tolerate a database that is still initializing.
8 minute lesson
A running database container may still be replaying logs or creating its first database. Process state alone does not mean the service is ready.
A health check tests useful behavior. Compose can wait for a dependency to become healthy, but the application should still retry temporary connection failures because services can restart after initial startup.
database:
healthcheck:
test: ["CMD-SHELL", "pg_isready -U notes -d notes"]
interval: 5s
timeout: 3s
retries: 10
api:
depends_on:
database:
condition: service_healthy
The health command runs inside the database container, so it must use tools available in that image and test the same behavior the application needs. Keep it fast, read-only, and specific. A check that always succeeds proves nothing; a heavyweight check can create its own outage.
Use docker inspect to see recent probe results when a service remains unhealthy:
docker inspect database --format '{{json .State.Health}}'
Startup ordering is only an initial convenience. Connections can fail after both services are healthy, so the API still needs bounded retries with backoff, useful logs, and a clear terminal failure. Health checks should expose a problem, not replace application resilience.
Add the health check, recreate the stack, and watch docker compose ps while PostgreSQL changes from starting to healthy.
Lesson completed