What happens when the App runs faster than the DB?
When I first started building microservices for an e-commerce platform, I hit a really frustrating issue. Every time I maintained the server or typed docker-compose up -d, the Node.js application would crash repeatedly. The logs showed bright red Connection Refused errors, even though I had carefully included depends_on: - db in my Compose file.
After spending the whole night scanning logs, I realized the truth: Docker only cares if the DB container is in a Running state. It has no idea if the MySQL or Postgres service inside has actually “opened its doors” for business. In reality, MySQL 8.0 usually takes about 12-15 seconds to initialize the database for the first time, while our App only takes 2 seconds to fire up. The result? The App calls the DB while it’s still busy loading configurations, and… crash!
To fix this once and for all, we need the duo of (advanced) depends_on and healthcheck. This is how you help your container cluster coordinate smoothly without manual intervention.
“Real-world” Docker Compose Configuration
If you want to apply this right away, here is a standard template to force the Web App to wait until Postgres is actually READY, not just running.
version: '3.8'
services:
db:
image: postgres:15
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: password
POSTGRES_DB: my_app
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d my_app"]
interval: 5s
timeout: 5s
retries: 5
start_period: 10s
web-app:
build: .
depends_on:
db:
condition: service_healthy
environment:
DATABASE_URL: postgres://user:password@db:5432/my_app
Adding these few healthcheck lines will save you at least 3 manual server restarts every time you deploy new code. Extremely worth it!
Why is depends_on alone not enough?
Many people new to Docker assume that depends_on handles everything. However, the Docker Engine only manages at the process level.
- Container Layer: Docker reports the container as running because the main process (PID 1) has started.
- Application Layer: Heavy services like Java Spring Boot or Oracle DB need time to load configurations, bind to ports, and be ready to handle requests.
Docker cannot see inside to know if your App is okay unless you tell it how to check. That is why Health Check was born.
Deep Dive into Health Check – The Dedicated “Security Guard”
Imagine Health Check is a security guard who checks on the container every 5 seconds: “Are you alive?”. If the container answers with the right code (exit code 0), it is labeled healthy. If it stays silent for too long, it’s considered “beyond saving”.
Parameters you need to fine-tune:
test: The check command. Can usecurlto call an API or internal commands likemysqladmin ping.interval: Check frequency. Don’t set it too low (like 1s) to avoid wasting CPU.timeout: Max wait time for a response before it’s considered a failure.retries: Number of consecutive retries before Docker officially reports the container as failed.start_period: The “grace period.” During this time, failures are ignored by Docker. Essential for heavy apps like Magento or Java that start very slowly.
Customization Tips for Each Service Type
Each type of service has its own way of being “polled”. Here are some templates I often copy-paste into projects:
1. For MySQL / MariaDB
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
retries: 3
2. For Redis
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
3. For Web APIs (Node.js, Python, Go)
If the App doesn’t have a built-in check tool, install curl in the Dockerfile and create a simple /health endpoint:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
Practical Experience: Don’t Rely Entirely on Docker
After running systems in production for a long time, I’ve gathered 3 painful lessons for you:
First: Always have Retry Logic in your code. No matter how good Docker Compose is, the internal network can still lag. DB connection code should have a retry loop (about 5-10 times) before deciding to stop. This helps the system recover very well.
Second: Avoid heavy Health Checks. Don’t be foolish enough to write a check command that runs a SQL query on millions of records. If every check causes a CPU spike, it does more harm than good. Just use the lightest commands like ping.
Third: Check the Compose version. The condition: service_healthy feature requires Docker Compose file 3.x or higher. If you’re still using a version from the “Stone Age”, upgrade now to enjoy this convenience.
Summary of Common Mistakes
To wrap up, here are the 3 mistakes I see most often:
- Only using the short-form
depends_onlist and expecting it to wait for the App to be ready. - Forgetting to set
start_period, causing Docker to think the container is failing and restart it repeatedly (boot loop). - Setting
timeouttoo low while the server disk is congested (I/O wait), leading to false positives.
Mastering this duo not only makes your configuration files more professional but also helps you sleep better, without worrying about being woken up in the middle of the night because the server just restarted. Happy smooth setup!

