Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A better wait-for-postgres.sh
#!/bin/bash -e
# wait-for-postgres.sh
# Adapted from https://docs.docker.com/compose/startup-order/
# Expects the necessary PG* variables.
until psql -c '\l'; do
echo >&2 "$(date +%Y%m%dt%H%M%S) Postgres is unavailable - sleeping"
sleep 1
done
echo >&2 "$(date +%Y%m%dt%H%M%S) Postgres is up - executing command"
exec ${@}
@srghma

This comment has been minimized.

Copy link

srghma commented Nov 14, 2018

here's better variant

#!/bin/sh -e

# MIT
# idea stolen from https://gist.github.com/nicerobot/1136dcfba6ce3da67ce3ded5101a4078

# USAGE
# DBNAME=postgres://... ./wait-for-postgres

# Retries a command on failure (idea stolen from http://fahdshariff.blogspot.com/2014/02/retrying-commands-in-shell-scripts.html).
# $1 - the max number of attempts
# $2 - the seconds to sleep
# $3... - the command to run
retry() {
  max_attempts="$1"; shift
  seconds="$1"; shift
  cmd="$@"
  attempt_num=1

  until $cmd
  do
    if [ $attempt_num -eq $max_attempts ]
    then
      echo "Attempt $attempt_num failed and there are no more attempts left!"
      return 1
    else
      echo "Attempt $attempt_num failed! Trying again in $seconds seconds..."
      attempt_num=`expr "$attempt_num" + 1`
      sleep "$seconds"
    fi
  done
}

retry 5 1 psql --dbname=$DBNAME -c '\l' >/dev/null

echo >&2 "$(date +%Y%m%dt%H%M%S) Postgres is up - executing command"

exec ${@}
@nicerobot

This comment has been minimized.

Copy link
Owner Author

nicerobot commented Jan 12, 2019

"Better" is subjective. It's more versatile maybe. That doesn't always mean better ;-) Simplicity also matters and I didn't need a retry limit.

Also, I wouldn't provide the --dbname flag. psql supports PG* environment variables. Let the caller provide them in the way psql already expects.

I would also adhere to a different Bash style.

So if you want retries and want a truly better variant, I would write it like this:

#!/usr/bin/env bash

set -o errexit
set -o nounset
set -o pipefail

retry() {
  max_attempts="${1}"; shift
  retry_delay_seconds="${1}"; shift
  cmd="${@}"
  attempt_num=1

  until ${cmd}; do
    (( attempt_num >= max_attempts )) && {
      echo "Attempt ${attempt_num} failed and there are no more attempts left!"
      return 1
    }
    echo "Attempt ${attempt_num} failed! Trying again in ${retry_delay_seconds} seconds..."
    attempt_num=$[ attempt_num + 1 ]
    sleep ${retry_delay_seconds}
  done
}

retry 1>&2 ${MAX_ATTEMPTS:-5} ${RETRY_DELAY_SECONDS:-1} psql -c '\l'

psql "${@}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.