In this lesson, you will learn how to orchestrate service startup sequences so your application waits until its dependencies are truly ready to accept traffic, preventing connection crashes.
The "Race Condition" Problem
When you use depends_on in Docker Compose, Docker only ensures that a container starts, not that the application inside it is ready. If your Web App tries to connect to a Database the millisecond the Database container starts, the database might still be initializing its internal storage or schema. This leads to frustrating "Connection Refused" errors and application crashes during the boot sequence.
Using Health Check Waiters
To solve this, we combine healthcheck with the condition attribute in your depends_on configuration. By defining a custom healthcheck for your database, you tell Docker exactly what "ready" looks like (e.g., executing a command that successfully pings the database port). Then, you force the Web App to wait until that specific health check returns a healthy status.
Here is how you define that dependency:
services:
database:
image: postgres:15
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
web-app:
image: my-app:latest
depends_on:
database:
condition: service_healthy
In this setup, the web-app will not enter the running state until the database service confirms it has passed its pg_isready check.
Why This Matters
By implementing these "waiters," you eliminate the need for brittle sleep commands or complex retry logic inside your application code. Your infrastructure becomes self-healing and predictable: the Web App only attempts to initiate connections when the environment is stable. This significantly reduces startup latency caused by crash-looping containers that are forced to restart because they tried to connect too early.
Key Takeaway: Use condition: service_healthy in your depends_on block to turn passive service dependencies into active, sequence-aware startup orchestrations.