Skip to content

Instantly share code, notes, and snippets.

@reacocard
Last active September 18, 2023 15:32
Show Gist options
  • Save reacocard/28611bfaa2395072119464521d48729a to your computer and use it in GitHub Desktop.
Save reacocard/28611bfaa2395072119464521d48729a to your computer and use it in GitHub Desktop.
Bash retry function with exponential backoff.
#!/usr/bin/env bash
# This software is freely available under the Apache 2.0 license.
# Full license available here: https://www.apache.org/licenses/LICENSE-2.0.txt
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, 2, 4, 8, 16, etc. seconds.
# If multiplier is 5000, sleep intervals are 5, 10, 20, 40, 80, etc. seconds.
function err_retry() {
local exit_code=$1
local attempts=$2
local sleep_millis=$3
shift 3
for attempt in `seq 1 $attempts`; do
if [[ $attempt -gt 1 ]]; then
echo "Attempt $attempt of $attempts"
fi
# This weird construction lets us capture return codes under -o errexit
"$@" && local rc=$? || local rc=$?
if [[ ! $rc -eq $exit_code ]]; then
return $rc
fi
if [[ $attempt -eq $attempts ]]; then
return $rc
fi
local sleep_ms="$(($attempt * $attempt * $sleep_millis))"
sleep "${sleep_ms:0:-3}.${sleep_ms: -3}"
done
}
## Basic tests.
function arg_fail() {
echo $2
return $1
}
err_retry 2 5 100 arg_fail 2 "fail" || true
err_retry 2 5 1 arg_fail 1 "other_fail" || true
err_retry 2 5 1 arg_fail 0 "succeed" || true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment