1

I am trying to run my app which depends_on my Postgresql in Docker let say my database PostgreSQL not running now

and in my docker-compose.yml:

version: "3"
services:
  myapp:
    depends_on:
      - db
    container_name: myapp
    build:
      context: .
      dockerfile: Dockerfile
    restart: on-failure
    ports:
      - "8100:8100"

  db:
    container_name: postgres
    restart: on-failure
    image: postgres:10-alpine
    ports:
      - "5555:5432"
    environment:
      POSTGRES_USER: myuser
      POSTGRES_PASSWORD: 12345678
      POSTGRES_DB: dev

when I try docker-compose up -d yes it created the postgres and then create that myapp service but it seems my Postgresql is not running yet, after finish install and running myapp, it said:

my database server not running yet

how to make myapp running until that db service know that my db running ??

certual
  • 87
  • 9

2 Answers2

2

The documentation of depends_on says that:

depends_on does not wait for db to be “ready” before starting myapp - only until it have been started.

So you'll have to check that your database is ready by yourself before running your app.

Docker has a documentation that explains how to write a wrapper script to do that:

#!/bin/sh
# wait-for-postgres.sh

set -e

host="$1"
shift
cmd="$@"

until PGPASSWORD=$POSTGRES_PASSWORD psql -h "$host" -U "postgres" -c '\q'; do
  >&2 echo "Postgres is unavailable - sleeping"
  sleep 1
done

>&2 echo "Postgres is up - executing command"
exec $cmd

Then you can just call this script before running your app in your docker-compose file:

command: ["./wait-for-postgres.sh", "db", "python", "app.py"]

There are also tools such as wait-for-it, dockerize or wait-for.


However these solutions has some limitations and Docker says that:

The best solution is to perform this check in your application code, both at startup and whenever a connection is lost for any reason.

This method will be more resilient.

Here is how I use a retry strategy in javascript:

  async ensureConnection () {
    let retries = 5
    const interval = 1000

    while (retries) {
      try {
        await this.utils.raw('SELECT \'ensure connection\';')
        break
      } catch (err) {
        console.error(err)
        retries--
        console.info(`retries left: ${retries}, interval: ${interval} ms`)
        if (retries === 0) {
          throw err
        }
        await new Promise(resolve => setTimeout(resolve, interval))
      }
    }
  }
Mickael B.
  • 4,755
  • 4
  • 24
  • 48
  • what the mean command "db" in you said above? i am tring to understand , let say i have username=foo and password=bar and db_name=prod with port=555 and host=local, how can i use it in that script?? – certual Jan 21 '20 at 11:28
  • @mickael-b - you edited your answer to include all that I've wrote, so would thoughtful to refer to that. – Ultcyber Jan 21 '20 at 13:21
  • 1
    `db` is the hostname of the container. you can provide flags to the `psql` command: the host using `-h`, the port `-p`, the database `-d` the username `-U` and the password you can use the `PGPASSWORD` environment variable. – Mickael B. Jan 21 '20 at 13:25
  • @certual - you need to add a POSTGRES_PASSWORD to your environment variables with value "bar", in the script that @mickael-b posted replace `-U postgres` with `-U foo` and put your port in the script like this: `command: ["./wait-for-postgres.sh", "url-to-your-db/prod:5555", "python", "app.py"]` – Ultcyber Jan 21 '20 at 13:26
  • @Ultcyber Hi, I didn't saw your answer I've quoted the official documentation. Also you might want to extract the essential information from your link. See [answer] and https://meta.stackexchange.com/questions/7656/how-do-i-write-a-good-answer-to-a-question – Mickael B. Jan 21 '20 at 13:52
  • @MickaelB. Ok, no worries, thanks for the advice – Ultcyber Jan 21 '20 at 14:57
  • must the port be the end of the last sentence? @Ultcyber – certual Jan 21 '20 at 18:21
  • yes, you need to specify the port @certual – Ultcyber Jan 22 '20 at 08:30
0

Please have a look at: https://docs.docker.com/compose/startup-order/.

Docker-compose won't wait for your database, you need a way to check it externally (via script or retrying the connection as Mickael B. proposed). One of the solutions proposed in the above link is a wait-for.sh utility script - we used it in a project and it worked quite well.

Ultcyber
  • 396
  • 1
  • 6