diff --git a/thousandeyes-sdk-client/src/thousandeyes_sdk/client/thousandeyes_retry.py b/thousandeyes-sdk-client/src/thousandeyes_sdk/client/thousandeyes_retry.py index 53d6098c..b27a5a14 100644 --- a/thousandeyes-sdk-client/src/thousandeyes_sdk/client/thousandeyes_retry.py +++ b/thousandeyes-sdk-client/src/thousandeyes_sdk/client/thousandeyes_retry.py @@ -1,7 +1,6 @@ import re import time -import typing -from typing import Optional, Union +from typing import Collection, Optional, Union from urllib3 import BaseHTTPResponse from urllib3.util.retry import RequestHistory, Retry @@ -13,15 +12,18 @@ class ThousandEyesRetry(Retry): "x-instant-test-rate-limit-reset" } + RESET_HEADER_PATTERN = re.compile(r"^\s*[0-9]+\s*$") + HTTP_TOO_MANY_REQUESTS = 429 + def __init__( self, - total: Union[bool, int, None] = 10, + total: Union[bool, int, None] = 3, connect: Optional[int] = None, read: Optional[int] = None, redirect: Union[bool, int, None] = None, - status: Optional[int] = None, + status: Optional[int] = 1, other: Optional[int] = None, - allowed_methods: Optional[typing.Collection[str]] = Retry.DEFAULT_ALLOWED_METHODS, + allowed_methods: Optional[Collection[str]] = Retry.DEFAULT_ALLOWED_METHODS, status_forcelist=None, backoff_factor: float = 0, backoff_max: float = Retry.DEFAULT_BACKOFF_MAX, @@ -29,16 +31,18 @@ class ThousandEyesRetry(Retry): raise_on_status: bool = False, history: Optional[tuple[RequestHistory, ...]] = None, respect_retry_after_header: bool = True, - remove_headers_on_redirect: typing.Collection[ - str - ] = Retry.DEFAULT_REMOVE_HEADERS_ON_REDIRECT, + remove_headers_on_redirect: Collection[str] = Retry.DEFAULT_REMOVE_HEADERS_ON_REDIRECT, backoff_jitter: float = 0.0) -> None: super().__init__(total, connect, read, redirect, status, other, allowed_methods, - [429] if status_forcelist is None else status_forcelist, - backoff_factor, backoff_max, raise_on_redirect, + status_forcelist, backoff_factor, backoff_max, raise_on_redirect, raise_on_status, history, respect_retry_after_header, remove_headers_on_redirect, backoff_jitter) + def is_retry(self, method: str, status_code: int, has_retry_after: bool = False) -> bool: + ret = super().is_retry(method, status_code, has_retry_after) + # Always retry on 429, regardless of method or status_forcelist + return ret or status_code == 429 + def get_retry_after(self, response: BaseHTTPResponse) -> Optional[float]: retry_after: Optional[float] = super().get_retry_after(response) @@ -52,9 +56,8 @@ class ThousandEyesRetry(Retry): return retry_after - @staticmethod - def _parse_reset_header(value: Optional[str]) -> Optional[float]: - if value is None or not re.match(r"^\s*[0-9]+\s*$", value): + def _parse_reset_header(self, value: Optional[str]) -> Optional[float]: + if value is None or not self.RESET_HEADER_PATTERN.match(value): return None seconds: float = int(value) - time.time()