retry.sh 1.18 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#!/usr/bin/env bash

# Inspired by https://gist.github.com/reacocard/28611bfaa2395072119464521d48729a

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

# Retry a command on a particular exit code, up to a max number of attempts,
# with exponential backoff.
# Invocation:
#   err_retry exit_code attempts sleep_multiplier <command>
# exit_code: The exit code to retry on.
# attempts: The number of attempts to make.
# sleep_millis: Multiplier for sleep between attempts. Examples:
#     If multiplier is 1000, sleep intervals are 1, 4, 9, 16, etc. seconds.
#     If multiplier is 5000, sleep intervals are 5, 20, 45, 80, 125, etc. seconds.

exit_code=$1
attempts=$2
sleep_millis=$3
shift 3

for attempt in `seq 1 $attempts`; do
    # This weird construction lets us capture return codes under -o errexit
    "$@" && rc=$? || rc=$?

    if [[ ! $rc -eq $exit_code ]]; then
        exit $rc
    fi

    if [[ $attempt -eq $attempts ]]; then
        exit $rc
    fi

    sleep_ms="$(($attempt * $attempt * $sleep_millis))"

Sidney Keese's avatar
Sidney Keese committed
38
39
    sleep_seconds=$(echo "scale=2; ${sleep_ms}/1000" | bc)

40
    (>&2 echo "sleeping ${sleep_seconds}s and then retrying ($((attempt + 1))/${attempts})")
41

Sidney Keese's avatar
Sidney Keese committed
42
    sleep "${sleep_seconds}"
43
done