retry/retry

161 lines
4.0 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env sh
GETOPT_BIN=$IN_GETOPT_BIN
GETOPT_BIN=${GETOPT_BIN:-getopt}
__sleep_amount() {
if [ -n "$constant_sleep" ]; then
sleep_time=$constant_sleep
else
#TODO: check for awk
#TODO: check if user would rather use one of the other possible dependencies: python, ruby, bc, dc
sleep_time=$(awk "BEGIN {t = $min_sleep * $((1 << (_retry_attempts - 1))); print (t > $max_sleep ? $max_sleep : t)}")
fi
}
__log_out() {
echo "$1" 1>&2
}
# Parameters: max_tries min_sleep max_sleep constant_sleep fail_script EXECUTION_COMMAND
retry() {
_retry_max_tries="$1"
shift
_retry_min_sleep="$1"
shift
_retry_max_sleep="$1"
shift
_retry_constant_sleep="$1"
shift
_retry_fail_script="$1"
shift
if [ -n "$VERBOSE" ]; then
__log_out "Retry Parameters: max_tries=$_retry_max_tries min_sleep=$_retry_min_sleep max_sleep=$_retry_max_sleep constant_sleep=$_retry_constant_sleep"
if [ -n "$_retry_fail_script" ]; then __log_out "Fail script: $_retry_fail_script"; fi
__log_out ""
__log_out "Execution Command: $*"
__log_out ""
fi
_retry_attempts=0
_retry_return_code=1
while [ "$_retry_return_code" -ne 0 ] && [ "$_retry_attempts" -le "$_retry_max_tries" ]; do
if [ $_retry_attempts -gt 0 ]; then
__sleep_amount
__log_out "Before retry #$_retry_attempts: sleeping $sleep_time seconds"
sleep "$sleep_time"
fi
P="$1"
#for param in "${@:2}"; do P="$P '$param'"; done
#TODO: replace single quotes in each arg with '"'"' ?
export RETRY_ATTEMPT=$_retry_attempts
sh -c "$P"
_retry_return_code=$?
#__log_out "Process returned $_retry_return_code on attempt $_retry_attempts"
if [ $_retry_return_code -eq 127 ]; then
# command not found
exit $_retry_return_code
elif [ $_retry_return_code -ne 0 ]; then
_retry_attempts=$((_retry_attempts + 1))
fi
done
if [ "$_retry_attempts" -gt "$_retry_max_tries" ]; then
if [ -n "$_retry_fail_script" ]; then
__log_out "Retries exhausted, running fail script"
eval "$_retry_fail_script"
else
__log_out "Retries exhausted"
fi
fi
exit $_retry_return_code
}
help() {
_help_retry=$(basename "$0")
cat <<EOF
Usage: $_help_retry [options] -- execute command
-h, -?, --help
-v, --verbose Verbose output
-t, --tries=# Set max retries: Default 10
-s, --sleep=secs Constant sleep amount (seconds)
-m, --min=secs Exponential Backoff: minimum sleep amount (seconds): Default 0.3
-x, --max=secs Exponential Backoff: maximum sleep amount (seconds): Default 60
-f, --fail="script +cmds" Fail Script: run in case of final failure
EOF
}
# show help for no arguments if stdin is a terminal
if { [ -z "$1" ] && [ -t 0 ]; } || [ "$1" = '-h' ] || [ "$1" = '-?' ] || [ "$1" = '--help' ]; then
help
exit 0
fi
$GETOPT_BIN --test >/dev/null
if [ $? -ne 4 ]; then
echo "Im sorry, 'getopt --test' failed in this environment. Please load GNU getopt."
exit 1
fi
OPTIONS=vt:s:m:x:f:
LONGOPTIONS=verbose,tries:,sleep:,min:,max:,fail:
PARSED=$($GETOPT_BIN --options="$OPTIONS" --longoptions="$LONGOPTIONS" --name "$0" -- "$@")
# shellcheck disable=SC2181
if [ $? -ne 0 ]; then
# e.g. $? == 1
# then getopt has complained about wrong arguments to stdout
exit 2
fi
# read getopts output this way to handle the quoting right:
eval set -- "$PARSED"
max_tries=10
min_sleep=0.3
max_sleep=60.0
constant_sleep=
fail_script=
# now enjoy the options in order and nicely split until we see --
while true; do
case "$1" in
-v | --verbose)
VERBOSE=true
shift
;;
-t | --tries)
max_tries="$2"
shift 2
;;
-s | --sleep)
constant_sleep="$2"
shift 2
;;
-m | --min)
min_sleep="$2"
shift 2
;;
-x | --max)
max_sleep="$2"
shift 2
;;
-f | --fail)
fail_script="$2"
shift 2
;;
--)
shift
break
;;
*)
echo "Programming error"
exit 3
;;
esac
done
retry "$max_tries" "$min_sleep" "$max_sleep" "$constant_sleep" "$fail_script" "$@"