Healthchecks

Healthchecks and Condition-Based Dependencies

A healthcheck is a command Docker 514 runs inside the container on a schedule; exit code 0 means healthy. The API's image has one (Planning Images), and a healthcheck: key adds one to an image that lacks it, such as postgres:18, whose pg_isready exists for this purpose:

compose.yaml: the API waits for a healthy databaseYAML
services:
  api:
    # ...build, ports and environment as before...
    depends_on:
      db:
        condition: service_healthy
        restart: true
  db:
    # ...image, environment, ports and volumes as before...
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
      interval: 10s
      timeout: 3s
      retries: 5
      start_period: 30s
      start_interval: 1s

CMD-SHELL runs the test through /bin/sh; $$ keeps Compose 514 from interpolating the container's variables. Five failures in a row mark the container unhealthy, failures during start_period do not count, and start_interval (Compose 2.20.2, Engine 25) probes every second until the first success. -h 127.0.0.1 matters: a first start initializes the database with a temporary server on a Unix socket only, which a socket-based check would call ready just before it shuts down. Start from an empty volume:

A clean first start: the API waits for a healthy databaseShell
docker compose down -v >/dev/null 2>&1
docker compose up -d 2>&1 | grep -E 'db-1 (Started|Healthy)|api-1 Started'
docker inspect l3-booknest-api-1 --format 'restarts: {{.RestartCount}}'
docker compose logs --no-log-prefix db | grep -E 'accept conn|shut down$|init process' \
  | sed -E 's/^[0-9-]+ ([0-9:.]+) UTC (\[[0-9]+\]) LOG: +/\1 \2 /'
Output
 Container l3-booknest-db-1 Started
 Container l3-booknest-db-1 Healthy
 Container l3-booknest-api-1 Started
restarts: 0
11:04:15.616 [60] database system is ready to accept connections
11:04:16.050 [60] database system is shut down
PostgreSQL init process complete; ready for start up.
11:04:16.136 [1] database system is ready to accept connections

The API started only once db was healthy and never restarted. The log shows the temporary server ready and shut down before the real one, PID 1 in the container, started.

What two depends_on conditions wait for during PostgreSQL's first start
What two depends_on conditions wait for during PostgreSQL 1,289 's first start

Keep healthchecks cheap and local: a check that calls another service turns one outage into two.