While working with Docker Compose to set up a containerized RSpec testing environment today, I ran into a problem.

RSpec, running in one container, was intermittently trying to access the PostgreSQL database, located in a second container, before it had finished booting. Naturally, this was causing sporadic connection errors and test failures.

The testing environment was distributed, with many discrete Docker Compose applications running in parallel. And PostgreSQL’s launch time varied considerably, sometimes being under a couple of seconds, but occasionally taking ten seconds or more.

This meant that naively setting a timeout (sleep 5 && bundle exec rspec…) was an unsatisfactory approach. It would have increased the run time of every test environment, but without completely solving the problem.

While researching the most appropriate solution, I discovered a useful tool. pg_isready allows a PostgreSQL database’s status to be queried quickly and simply from a script or the command line.

Once I’d found it, using it in the RSpec container’s entrypoint script was simple:

#!/bin/bash

set -e
echo "Launching Rails $RAILS_ENV environment with target: $@"

until pg_isready -q -d my_database_name
do
  echo "Waiting for database to be ready..."
  sleep 1
done

bundle exec rake db:reset
bundle exec rspec $@