Hendrik Jan
Hendrik Jan

Reputation: 4908

Docker-compose Laravel how to wait for the database to load?

I am trying to set up tests for my Laravel application.
The application runs with Docker compose.

When I try to start my tests with this command:

docker-compose -p tests --env-file .env_tests --rm run myapp ./vendor/bin/phpunit

the tests start to run before the database container is ready.
How can I make my tests wait for the database to become ready?

My docker-compose.yml looks like this:

version: '2'

services:
  mariadb:
    image: 'bitnami/mariadb:10.1'
    environment:
      - ALLOW_EMPTY_PASSWORD=yes
      - MARIADB_USER=my_user
      - MARIADB_DATABASE=my_database
      - MARIADB_PASSWORD=my_password
    ports:
      # connect your dbeaver/workbench to localhost:${WORKBENCH_PORT}
      - ${WORKBENCH_PORT}:3306
    # volumes:
      # Do not load databases here, as there is no
      # good way for other containers to wait for this to finish
      # - ./database:/docker-entrypoint-initdb.d
  myapp:
    tty: true
    image: bitnami/laravel:6-debian-9
    environment:
      - DB_HOST=mariadb
      - DB_USERNAME=my_user
      - DB_DATABASE=my_database
      - DB_PASSWORD=my_password
    depends_on:
      - mariadb
    ports:
      - 3000:3000
    volumes:
      - ./:/app

When I start the application normally (docker-compose up), Laravel waits for the mariadb container to finish loading, but I couldn't find out how this is done.

---- Edit ----
I found that the bitami/laravel Docker container that I use has a script called wait_for_db() that seems to wait for the database.
What I didn't find out yet is why this script is run in normal mode, but not when I start the tests.

Upvotes: 1

Views: 741

Answers (1)

miguescri
miguescri

Reputation: 71

According to the official docs, it is not possible to wait until the database is ready, but only until it has started:

However, for startup Compose does not wait until a container is “ready” (whatever that means for your particular application) - only until it’s running. There’s a good reason for this. (...) The best solution is to perform this check in your application code, both at startup and whenever a connection is lost for any reason.

The difference in your app's behaviour between the general case and the test case may be related to other reasons, such as the test taking less time to load (giving less time to the database to get ready) or test handling connection failure in a different way (not retrying after some time).

EDIT

Using docker-compose run overrides the entrypoint of the container. Therefore, even if originally there was a script intended to wait for the database initialization, it will not be run.

Check the docs of the command:

First, the command passed by run overrides the command defined in the service configuration. For example, if the web service configuration is started with bash, then docker-compose run web python app.py overrides it with python app.py.

Upvotes: 1

Related Questions