<!--
  canonical-url: https://www.avonture.be/blog/docker-health-condition
  published:     2024-03-23
  This is a static plain-Markdown mirror generated at build time.
  Visit the canonical URL above for the fully rendered page, with images and interactive components.
-->

# Understanding the depends_on condition in Docker compose files

> Prevent startup errors in your multi-service applications. Learn to use the healthcheck property and depends_on condition service_healthy in Docker Compose to ensure your application waits for the database to be fully ready before starting.

---
![Understanding the depends\_on condition in Docker compose files](/img/v2/docker_tips.webp)

**TL;DR**

This article explains how to prevent an application container from starting before its database is ready, using Docker Compose's `healthcheck` property (to define when a service is considered ready) combined with `depends_on: condition: service_healthy` on the dependent service — replacing fragile manual retry-loop scripts.

It's only been ten days or so since I learned the trick, even though it was well documented: managing service startups and, above all, blocking one if the other isn't ready ([official documentation](https://docs.docker.com/compose/startup-order/#control-startup)).

Imagine a two-service application like Joomla (see my [Create your Joomla website using Docker](/blog/docker-joomla/)), [WordPress](/blog/docker-wordpress), [LimeSurvey](/blog/docker-limesurvey), Laravel and many, many more use cases: you've an application and that application requires a database.

*This article is about **waiting** for a healthy service; [Get health information from your running containers](/blog/docker-healthy) is about **reading** that health status from the command line. And [FrankenPHP, a modern application server for PHP](/blog/frankenphp-docker-joomla) shows exactly the kind of "Connection refused" storm you get without it.*

You've, roughly speaking, a `compose.yaml` file like this:

**compose.yaml**

```yaml
services:
  joomla:
    image: joomla
    [...]

  joomladb:
    image: mysql:8.0.13
    [...]
```

And, yeah, it works. You can execute `docker compose up --detach` and wait until the two services are up and, sooner or later, you'll get your application ready.

But you have the intuition that something isn't quite right here... What happens if the database service is slow to load? You'd have the application (Joomla here, but it doesn't really matter) which, in its initialization process, is going to want to connect to the database, and wham! This will not work and you will receive *Error when connecting to the database* errors. With a bit of luck, the application will try several times before stopping in error. Without luck, the application will just crash.

How to solve this? The answer is in two parts.

1. You need to instruct Docker how he can know that the service is ready,
2. You need to pause the application service until the database is ready.

## The healthcheck property

The idea is to ask Docker to run a given command each xxx seconds until he gets a `Success` status (in terms of Linux, it's a command that returns an exit code equal to `0`).

By searching on the Internet using `docker healthcheck` followed by the name of a service (MySQL, PostgreSQL, Apache, Redis, ...), you'll find a lot of possibilities.

For MySQL, we'll use the next one:

**compose.yaml**

```yaml
services:
  joomla:
    image: joomla
    [...]

  joomladb:
    image: mysql:8.0.13
    [...]
    // highlight-next-line
    healthcheck:
      // highlight-next-line
      test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
      // highlight-next-line
      timeout: 20s
      // highlight-next-line
      retries: 10
```

The four lines above instruct Docker to check the command defined by the `test` property every 20 seconds, up to 10 times. While that command doesn't return `0`, the container is considered `unhealthy`. Then, hopefully, the command will return `0` and Docker will consider the service as `healthy`.

## The depends\_on property

Now, the second part is to create a dependency in our application. Back to the Joomla service (in our example), we'll add a `depends_on` property like below.

**compose.yaml**

```yaml
services:
  joomla:
    image: joomla
    [...]
    // highlight-next-line
    depends_on:
      // highlight-next-line
      joomladb:
        // highlight-next-line
        condition: service_healthy

  joomladb:
    image: mysql:8.0.13
    [...]
    healthcheck:
      test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
      timeout: 20s
      retries: 10
```

It's pretty self-explanatory, I think. Docker will pause the creation of the Joomla container (just the creation, not downloading the image or any previous step) while the `depends_on` service isn't healthy.

And do you know what? I'm mad I didn't know about this sooner, because I've already set up a script like the one below in my applications:

> **Very simplified script:**
>
> ```bash
> while [[ ! "$exitCode"  = "0" ]]; do
>   echo "Waiting MySQL to launch on 3306..."
>   exitCode="$(nc joomladb 3306)"
> done
> ```
