From 55f37dffe52d60c19522bca2ff79a2d5ed6632a1 Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Sat, 11 May 2024 15:43:32 +0200 Subject: [PATCH] oci: improve default_retry (#44132) Apparently urllib can throw a range of different exceptions: 1. HTTPError 2. URLError with e.reason set to the actual exception 3. TimeoutError from getresponse, which is not wrapped --- lib/spack/spack/oci/opener.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/spack/spack/oci/opener.py b/lib/spack/spack/oci/opener.py index 0717101274..53535b85ed 100644 --- a/lib/spack/spack/oci/opener.py +++ b/lib/spack/spack/oci/opener.py @@ -418,18 +418,27 @@ def ensure_status(request: urllib.request.Request, response: HTTPResponse, statu ) -def default_retry(f, retries: int = 3, sleep=None): +def default_retry(f, retries: int = 5, sleep=None): sleep = sleep or time.sleep def wrapper(*args, **kwargs): for i in range(retries): try: return f(*args, **kwargs) - except urllib.error.HTTPError as e: + except (urllib.error.URLError, TimeoutError) as e: # Retry on internal server errors, and rate limit errors # Potentially this could take into account the Retry-After header # if registries support it - if i + 1 != retries and (500 <= e.code < 600 or e.code == 429): + if i + 1 != retries and ( + ( + isinstance(e, urllib.error.HTTPError) + and (500 <= e.code < 600 or e.code == 429) + ) + or ( + isinstance(e, urllib.error.URLError) and isinstance(e.reason, TimeoutError) + ) + or isinstance(e, TimeoutError) + ): # Exponential backoff sleep(2**i) continue