Skip to content

Commit bcf1def

Browse files
authored
Merge pull request #138 from buildkite-plugins/Ola-Retry
SUP-5615: Add retry logic for binary download
2 parents a0c7ae2 + 367e897 commit bcf1def

File tree

3 files changed

+90
-3
lines changed

3 files changed

+90
-3
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,10 @@ steps:
305305
trigger: "deploy-foo-service"
306306
```
307307

308+
### Download Retry Behavior
309+
310+
The plugin automatically retries binary downloads up to 3 times with a 5-second delay between attempts. This handles transient network issues when downloading from GitHub.
311+
308312
### `hooks` (optional)
309313

310314
Currently supports a list of `commands` you wish to execute after the `watched` pipelines have been triggered

hooks/command

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
#!/usr/bin/env bash
22
set -euo pipefail
33

4+
# Retry configuration for downloads
5+
# Hardcoded values - meant for transient network issues, not hard outages
6+
max_retries=3
7+
retry_delay=5
8+
49
executable="monorepo-diff-buildkite-plugin"
510
executable_version_file="${executable}.version"
611

@@ -66,6 +71,29 @@ downloader() {
6671
fi
6772
}
6873

74+
# Retry wrapper for downloads (SUP-5615)
75+
download_with_retry() {
76+
local _url="$1"
77+
local _dest="$2"
78+
local _attempt=1
79+
80+
while [ $_attempt -le "$max_retries" ]; do
81+
say "Downloading binary (attempt ${_attempt}/${max_retries})..."
82+
if downloader "$_url" "$_dest"; then
83+
say "Download successful"
84+
return 0
85+
fi
86+
87+
if [ $_attempt -lt "$max_retries" ]; then
88+
say "Download failed, retrying in ${retry_delay} seconds..."
89+
sleep "$retry_delay"
90+
fi
91+
_attempt=$((_attempt + 1))
92+
done
93+
94+
return 1
95+
}
96+
6997
get_latest_version() {
7098
local _repo="https://api.github.com/repos/buildkite-plugins/monorepo-diff-buildkite-plugin"
7199
local _version=""
@@ -143,14 +171,14 @@ download_binary_and_run() {
143171
fi
144172

145173
if [ -n "${_url}" ]; then
146-
if ! downloader "$_url" "${executable}"; then
147-
say "failed to download $_url"
174+
# Use retry wrapper for resilient downloads (SUP-5615)
175+
if ! download_with_retry "$_url" "${executable}"; then
176+
say "Failed to download $_url after ${max_retries} attempts"
148177
exit 1
149178
fi
150179
echo "${_binary_version}" > "${executable_version_file}"
151180
fi
152181

153-
# todo: move it to a more secure place
154182
chmod +x "${executable}"
155183

156184
./"${executable}"

tests/command.bats

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,58 @@ teardown() {
9494
# Clean up stub (it should not have been called)
9595
unstub curl || true
9696
}
97+
98+
# Tests for download_with_retry() function (SUP-5615)
99+
100+
@test "download retries on transient failure and succeeds" {
101+
export BUILDKITE_PLUGIN_MONOREPO_DIFF_DOWNLOAD=true
102+
export BUILDKITE_PLUGIN_MONOREPO_DIFF_BUILDKITE_PLUGIN_TEST_MODE=false
103+
# Use pinned version to skip get_latest_version API call
104+
export BUILDKITE_PLUGINS='[{"github.com/buildkite-plugins/monorepo-diff-buildkite-plugin#v1.0.0": {}}]'
105+
106+
# Remove mock binary so it actually needs to download
107+
rm -f "$PWD/monorepo-diff-buildkite-plugin"
108+
rm -f "$PWD/monorepo-diff-buildkite-plugin.version"
109+
110+
# Stub curl: fail twice on download, then succeed and create executable
111+
stub curl \
112+
"-sSfL * -o * : exit 1" \
113+
"-sSfL * -o * : exit 1" \
114+
"-sSfL * -o * : echo '#!/bin/bash' > \"\${4}\"; echo 'echo test' >> \"\${4}\"; exit 0"
115+
116+
run "$PWD/hooks/command"
117+
118+
assert_output --partial "Downloading binary (attempt 1/3)"
119+
assert_output --partial "Download failed, retrying"
120+
assert_output --partial "Downloading binary (attempt 2/3)"
121+
assert_output --partial "Downloading binary (attempt 3/3)"
122+
assert_output --partial "Download successful"
123+
124+
unstub curl
125+
}
126+
127+
@test "download fails after max retries exhausted" {
128+
export BUILDKITE_PLUGIN_MONOREPO_DIFF_DOWNLOAD=true
129+
export BUILDKITE_PLUGIN_MONOREPO_DIFF_BUILDKITE_PLUGIN_TEST_MODE=false
130+
# Use pinned version to skip get_latest_version API call
131+
export BUILDKITE_PLUGINS='[{"github.com/buildkite-plugins/monorepo-diff-buildkite-plugin#v1.0.0": {}}]'
132+
133+
# Remove mock binary so it actually needs to download
134+
rm -f "$PWD/monorepo-diff-buildkite-plugin"
135+
136+
# Stub curl to always fail on download
137+
stub curl \
138+
"-sSfL * -o * : exit 1" \
139+
"-sSfL * -o * : exit 1" \
140+
"-sSfL * -o * : exit 1"
141+
142+
run "$PWD/hooks/command"
143+
144+
assert_failure
145+
assert_output --partial "Downloading binary (attempt 1/3)"
146+
assert_output --partial "Downloading binary (attempt 2/3)"
147+
assert_output --partial "Downloading binary (attempt 3/3)"
148+
assert_output --partial "Failed to download"
149+
150+
unstub curl
151+
}

0 commit comments

Comments
 (0)