Skip to content

Commit 9afef01

Browse files
authored
[#31426] build: Retry thirdparty downloads at the Python level on any curl failure (#31427)
## Summary Thirdparty archive downloads occasionally fail with curl exit status 22 on GitHub Actions because curl's `--retry` only retries timeouts and HTTP 408/429/5xx, not transient 403s on GitHub's signed release-asset redirects. `--retry-all-errors` would cover this but requires curl >= 7.71.0, which is unavailable on AlmaLinux 8 / RHEL 8 (curl 7.61.1) and similar runners. Wrap the curl invocation in a Python retry loop instead, so any curl failure is retried regardless of curl version. Fixes #31426. ## Test Plan Jenkins: compile only --- [CSI](<https://csiweb.dev.yugabyte.com/pull/31427/>)
1 parent 35a565d commit 9afef01

1 file changed

Lines changed: 18 additions & 14 deletions

File tree

python/yugabyte/download_and_extract_archive.py

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -131,20 +131,24 @@ def download_url(url: str, dest_path: str, other_curl_flags: List[str] = []) ->
131131
dest_dir = os.path.dirname(dest_path)
132132
if not os.path.isdir(dest_dir):
133133
raise IOError("Destination directory %s does not exist" % dest_dir)
134-
# -f / --fail: don't write the response body for HTTP error responses, so we don't end up
135-
# with an HTML error page on disk masquerading as the requested artifact.
136-
# --retry / --retry-delay: retry transient failures (5xx, connection errors) before giving up.
137-
# Note: curl --retry counts retries after the initial attempt, so we pass
138-
# MAX_DOWNLOAD_ATTEMPTS - 1 to get MAX_DOWNLOAD_ATTEMPTS total attempts.
139-
# --retry-connrefused: also retry on ECONNREFUSED, which curl does not retry by default
140-
# and which is a common transient failure in CI environments.
141-
run_cmd([
142-
'curl', '-LsSf',
143-
'--retry', str(MAX_DOWNLOAD_ATTEMPTS - 1),
144-
'--retry-delay', str(RETRY_DELAY_SEC),
145-
'--retry-connrefused',
146-
url, '-o', dest_path,
147-
] + other_curl_flags)
134+
# -f: exit 22 on HTTP errors instead of saving the error page as the artifact.
135+
# Retry at the Python level so any curl failure is retried, including transient
136+
# non-5xx HTTP errors (e.g. 403s on GitHub's signed release-asset redirects)
137+
# that curl's --retry skips. --retry-all-errors would cover this but requires
138+
# curl >= 7.71.0, which is unavailable on AlmaLinux 8 / RHEL 8 and similar.
139+
cmd = ['curl', '-LsSf', url, '-o', dest_path] + other_curl_flags
140+
for attempt in range(1, MAX_DOWNLOAD_ATTEMPTS + 1):
141+
try:
142+
run_cmd(cmd)
143+
break
144+
except subprocess.CalledProcessError as ex:
145+
if attempt == MAX_DOWNLOAD_ATTEMPTS:
146+
raise
147+
logging.warning(
148+
"curl failed downloading %s (attempt %d/%d) with exit code %d, "
149+
"retrying in %ds",
150+
url, attempt, MAX_DOWNLOAD_ATTEMPTS, ex.returncode, RETRY_DELAY_SEC)
151+
time.sleep(RETRY_DELAY_SEC)
148152
if not os.path.exists(dest_path):
149153
raise IOError("Failed to download %s: file %s does not exist" % (url, dest_path))
150154
elapsed_sec = time.time() - start_time_sec

0 commit comments

Comments
 (0)