Docker cookbook · Beginner
Make containers cope with dependencies that start slowly
The app crashes when the database isn't ready yet, in Compose and after database restarts.
Approach
Use healthchecks with service_healthy for startup order in Compose, and make the application retry
connections with backoff, because dependencies also restart in production.
Solution
import time
import psycopg
def connect(dsn, attempts=30):
delay = 0.5
for attempt in range(1, attempts + 1):
try:
return psycopg.connect(dsn, connect_timeout=3)
except psycopg.OperationalError as exc:
if attempt == attempts:
raise
print(f"database not ready ({exc.__class__.__name__}), retrying in {delay:.1f}s", flush=True)
time.sleep(delay)
delay = min(delay * 2, 5)
Pitfalls
- Shell
wait-for-itscripts as the only protection; they don't help when the database restarts later. - Retrying forever without logging, so a misconfiguration looks like a hang.
Variations
- Connection pools with built-in reconnect and health checks.
- Readiness endpoints that report "not ready" until dependencies are reachable.
Further reading: Control startup order
Reference: https://docs.docker.com/compose/how-tos/startup-order/
More Docker recipes
- Add a healthcheck to an HTTP service
- Build a layered image for a Spring Boot app
- Build a production image for a Node.js service
- Build a production image for a Python web app
- Build, cache and push images in GitHub Actions
- Build one image tag for amd64 and arm64
- Configure nginx from environment variables
- Develop with Compose and live reload