Skip to content

Commit 093db4c

Browse files
committed
fix(ci): stop download retries on explicit permanent errors
1 parent 75cf393 commit 093db4c

2 files changed

Lines changed: 36 additions & 0 deletions

File tree

‎dev/ci/retry-download.sh‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@ for attempt in 1 2 3 4; do
4444
exit 0
4545
fi
4646

47+
# An earlier connection warning may have recovered before a different download
48+
# failed permanently. Be conservative when both appear: a known permanent error
49+
# must not acquire retries just because the same attempt also logged a timeout.
50+
# Do not inspect only a fixed tail: Maven/SBT can print long failure summaries.
51+
if grep -Eiq \
52+
'(status code:|response code:|HTTP/[0-9.]+|HTTP error|returned error:)[[:space:]]*(400|401|403|404|405|410|422)([^0-9]|$)|Could not find artifact|not found: value|COMPILATION ERROR|There are test failures' \
53+
"$download_log"; then
54+
exit "$status"
55+
fi
56+
4757
# Signals (including cancellation and OOM kills) are not download failures.
4858
if [ "$status" -ge 128 ] || ! grep -Eiq \
4959
'(status code:|response code:|HTTP/[0-9.]+|HTTP error|returned error:)[[:space:]]*(429|500|502|503|504)([^0-9]|$)|Connection reset|Connection timed out|ConnectTimeoutException|SocketTimeoutException|Read timed out|Temporary failure in name resolution|Network is unreachable|Remote host terminated the handshake' \

‎dev/ci/test-download-retry.py‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,32 @@ def test_signal_exit_does_not_retry_even_after_network_message(self):
178178
self.assertEqual(len(calls), 1)
179179
self.assertEqual(delays, [])
180180

181+
def test_permanent_failure_overrides_earlier_transient_warning(self):
182+
for message in (
183+
"status code: 404, reason phrase: Not Found (404)",
184+
"Server returned HTTP response code: 403 for URL: https://repo.invalid/a.jar",
185+
"curl: (22) The requested URL returned error: 401",
186+
"[error] Could not find artifact missing:dependency:jar:1.0",
187+
"[error] not found: value invalidBuildSetting",
188+
"[ERROR] COMPILATION ERROR",
189+
"[ERROR] There are test failures.",
190+
):
191+
with self.subTest(message=message):
192+
self.calls.unlink(missing_ok=True)
193+
self.delays.unlink(missing_ok=True)
194+
output = f"[warn] Connection reset; recovered on retry\n{message}"
195+
result, calls, delays = self.run_download(output, failures=10, status=42)
196+
self.assertEqual(result.returncode, 42)
197+
self.assertEqual(len(calls), 1)
198+
self.assertEqual(delays, [])
199+
200+
def test_permanent_failure_is_not_hidden_by_long_summary(self):
201+
output = "Connection reset\nstatus code: 404\n" + "resolution details\n" * 1000
202+
result, calls, delays = self.run_download(output, failures=10, status=42)
203+
self.assertEqual(result.returncode, 42)
204+
self.assertEqual(len(calls), 1)
205+
self.assertEqual(delays, [])
206+
181207
def test_missing_command_fails(self):
182208
result = subprocess.run(["bash", str(RETRY)], capture_output=True, text=True)
183209
self.assertEqual(result.returncode, 2)

0 commit comments

Comments
 (0)