Skip to content

Commit fa0aac0

Browse files
author
MarcoFalke
committed
1 parent fafe78f commit fa0aac0

File tree

2 files changed

+286
-0
lines changed

2 files changed

+286
-0
lines changed

ci/retry/README.md

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
retry - The command line retry tool
2+
------------------------------------------
3+
4+
Retry any shell command with exponential backoff or constant delay.
5+
6+
### Instructions
7+
8+
Install:
9+
10+
retry is a shell script, so drop it somewhere and make sure it's added to your $PATH. Or you can use the following one-liner:
11+
12+
```sh
13+
sudo sh -c "curl https://raw.githubusercontent.com/kadwanev/retry/master/retry -o /usr/local/bin/retry && chmod +x /usr/local/bin/retry"
14+
```
15+
16+
If you're on OS X, retry is also on Homebrew:
17+
18+
```
19+
brew pull 27283
20+
brew install retry
21+
```
22+
Not popular enough for homebrew-core. Please star this project to help.
23+
24+
### Usage
25+
26+
Help:
27+
28+
`retry -?`
29+
30+
Usage: retry [options] -- execute command
31+
-h, -?, --help
32+
-v, --verbose Verbose output
33+
-t, --tries=# Set max retries: Default 10
34+
-s, --sleep=secs Constant sleep amount (seconds)
35+
-m, --min=secs Exponenetial Backoff: minimum sleep amount (seconds): Default 0.3
36+
-x, --max=secs Exponenetial Backoff: maximum sleep amount (seconds): Default 60
37+
-f, --fail="script +cmds" Fail Script: run in case of final failure
38+
39+
### Examples
40+
41+
No problem:
42+
43+
`retry echo u work good`
44+
45+
u work good
46+
47+
Test functionality:
48+
49+
`retry 'echo "y u no work"; false'`
50+
51+
y u no work
52+
Before retry #1: sleeping 0.3 seconds
53+
y u no work
54+
Before retry #2: sleeping 0.6 seconds
55+
y u no work
56+
Before retry #3: sleeping 1.2 seconds
57+
y u no work
58+
Before retry #4: sleeping 2.4 seconds
59+
y u no work
60+
Before retry #5: sleeping 4.8 seconds
61+
y u no work
62+
Before retry #6: sleeping 9.6 seconds
63+
y u no work
64+
Before retry #7: sleeping 19.2 seconds
65+
y u no work
66+
Before retry #8: sleeping 38.4 seconds
67+
y u no work
68+
Before retry #9: sleeping 60.0 seconds
69+
y u no work
70+
Before retry #10: sleeping 60.0 seconds
71+
y u no work
72+
etc..
73+
74+
Limit retries:
75+
76+
`retry -t 4 'echo "y u no work"; false'`
77+
78+
y u no work
79+
Before retry #1: sleeping 0.3 seconds
80+
y u no work
81+
Before retry #2: sleeping 0.6 seconds
82+
y u no work
83+
Before retry #3: sleeping 1.2 seconds
84+
y u no work
85+
Before retry #4: sleeping 2.4 seconds
86+
y u no work
87+
Retries exhausted
88+
89+
Bad command:
90+
91+
`retry poop`
92+
93+
bash: poop: command not found
94+
95+
Fail command:
96+
97+
`retry -t 3 -f 'echo "oh poopsickles"' 'echo "y u no work"; false'`
98+
99+
y u no work
100+
Before retry #1: sleeping 0.3 seconds
101+
y u no work
102+
Before retry #2: sleeping 0.6 seconds
103+
y u no work
104+
Before retry #3: sleeping 1.2 seconds
105+
y u no work
106+
Retries exhausted, running fail script
107+
oh poopsickles
108+
109+
Last attempt passed:
110+
111+
`retry -t 3 -- 'if [ $RETRY_ATTEMPT -eq 3 ]; then echo Passed at attempt $RETRY_ATTEMPT; true; else echo Failed at attempt $RETRY_ATTEMPT; false; fi;'`
112+
113+
Failed at attempt 0
114+
Before retry #1: sleeping 0.3 seconds
115+
Failed at attempt 1
116+
Before retry #2: sleeping 0.6 seconds
117+
Failed at attempt 2
118+
Before retry #3: sleeping 1.2 seconds
119+
Passed at attempt 3
120+
121+
### License
122+
123+
Apache 2.0 - go nuts

ci/retry/retry

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
#!/usr/bin/env bash
2+
3+
GETOPT_BIN=$IN_GETOPT_BIN
4+
GETOPT_BIN=${GETOPT_BIN:-getopt}
5+
6+
__sleep_amount() {
7+
if [ -n "$constant_sleep" ]; then
8+
sleep_time=$constant_sleep
9+
else
10+
#TODO: check for awk
11+
#TODO: check if user would rather use one of the other possible dependencies: python, ruby, bc, dc
12+
sleep_time=`awk "BEGIN {t = $min_sleep * $(( (1<<($attempts -1)) )); print (t > $max_sleep ? $max_sleep : t)}"`
13+
fi
14+
}
15+
16+
__log_out() {
17+
echo "$1" 1>&2
18+
}
19+
20+
# Paramters: max_tries min_sleep max_sleep constant_sleep fail_script EXECUTION_COMMAND
21+
retry()
22+
{
23+
local max_tries="$1"; shift
24+
local min_sleep="$1"; shift
25+
local max_sleep="$1"; shift
26+
local constant_sleep="$1"; shift
27+
local fail_script="$1"; shift
28+
if [ -n "$VERBOSE" ]; then
29+
__log_out "Retry Parameters: max_tries=$max_tries min_sleep=$min_sleep max_sleep=$max_sleep constant_sleep=$constant_sleep"
30+
if [ -n "$fail_script" ]; then __log_out "Fail script: $fail_script"; fi
31+
__log_out ""
32+
__log_out "Execution Command: $*"
33+
__log_out ""
34+
fi
35+
36+
local attempts=0
37+
local return_code=1
38+
39+
40+
while [[ $return_code -ne 0 && $attempts -le $max_tries ]]; do
41+
if [ $attempts -gt 0 ]; then
42+
__sleep_amount
43+
__log_out "Before retry #$attempts: sleeping $sleep_time seconds"
44+
sleep $sleep_time
45+
fi
46+
47+
P="$1"
48+
for param in "${@:2}"; do P="$P '$param'"; done
49+
#TODO: replace single quotes in each arg with '"'"' ?
50+
export RETRY_ATTEMPT=$attempts
51+
bash -c "$P"
52+
return_code=$?
53+
#__log_out "Process returned $return_code on attempt $attempts"
54+
if [ $return_code -eq 127 ]; then
55+
# command not found
56+
exit $return_code
57+
elif [ $return_code -ne 0 ]; then
58+
attempts=$[$attempts +1]
59+
fi
60+
done
61+
62+
if [ $attempts -gt $max_tries ]; then
63+
if [ -n "$fail_script" ]; then
64+
__log_out "Retries exhausted, running fail script"
65+
eval $fail_script
66+
else
67+
__log_out "Retries exhausted"
68+
fi
69+
fi
70+
71+
exit $return_code
72+
}
73+
74+
# If we're being sourced, don't worry about such things
75+
if [ "$BASH_SOURCE" == "$0" ]; then
76+
# Prints the help text
77+
help()
78+
{
79+
local retry=$(basename $0)
80+
cat <<EOF
81+
Usage: $retry [options] -- execute command
82+
-h, -?, --help
83+
-v, --verbose Verbose output
84+
-t, --tries=# Set max retries: Default 10
85+
-s, --sleep=secs Constant sleep amount (seconds)
86+
-m, --min=secs Exponenetial Backoff: minimum sleep amount (seconds): Default 0.3
87+
-x, --max=secs Exponenetial Backoff: maximum sleep amount (seconds): Default 60
88+
-f, --fail="script +cmds" Fail Script: run in case of final failure
89+
EOF
90+
}
91+
92+
# show help for no arguments if stdin is a terminal
93+
if { [ -z "$1" ] && [ -t 0 ] ; } || [ "$1" == '-h' ] || [ "$1" == '-?' ] || [ "$1" == '--help' ]
94+
then
95+
help
96+
exit 0
97+
fi
98+
99+
$GETOPT_BIN --test > /dev/null
100+
if [[ $? -ne 4 ]]; then
101+
echo "I’m sorry, 'getopt --test' failed in this environment. Please load GNU getopt."
102+
exit 1
103+
fi
104+
105+
OPTIONS=vt:s:m:x:f:
106+
LONGOPTIONS=verbose,tries:,sleep:,min:,max:,fail:
107+
108+
PARSED=$($GETOPT_BIN --options="$OPTIONS" --longoptions="$LONGOPTIONS" --name "$0" -- "$@")
109+
if [[ $? -ne 0 ]]; then
110+
# e.g. $? == 1
111+
# then getopt has complained about wrong arguments to stdout
112+
exit 2
113+
fi
114+
# read getopt’s output this way to handle the quoting right:
115+
eval set -- "$PARSED"
116+
117+
max_tries=10
118+
min_sleep=0.3
119+
max_sleep=60.0
120+
constant_sleep=
121+
fail_script=
122+
123+
# now enjoy the options in order and nicely split until we see --
124+
while true; do
125+
case "$1" in
126+
-v|--verbose)
127+
VERBOSE=true
128+
shift
129+
;;
130+
-t|--tries)
131+
max_tries="$2"
132+
shift 2
133+
;;
134+
-s|--sleep)
135+
constant_sleep="$2"
136+
shift 2
137+
;;
138+
-m|--min)
139+
min_sleep="$2"
140+
shift 2
141+
;;
142+
-x|--max)
143+
max_sleep="$2"
144+
shift 2
145+
;;
146+
-f|--fail)
147+
fail_script="$2"
148+
shift 2
149+
;;
150+
--)
151+
shift
152+
break
153+
;;
154+
*)
155+
echo "Programming error"
156+
exit 3
157+
;;
158+
esac
159+
done
160+
161+
retry "$max_tries" "$min_sleep" "$max_sleep" "$constant_sleep" "$fail_script" "$@"
162+
163+
fi

0 commit comments

Comments
 (0)