63 lines
1.5 KiB
Python

from typing import Any, Callable, Type
import requests
from requests.exceptions import ConnectionError, Timeout
from tenacity import (
retry,
retry_if_exception,
retry_if_exception_type,
stop_after_attempt,
wait_exponential,
)
def is_server_error(exception):
return (
isinstance(exception, requests.HTTPError)
and exception.response.status_code >= 500
)
def is_404_error(exception):
return (
isinstance(exception, requests.HTTPError)
and exception.response.status_code == 404
)
DEFAULT_RETRY_EXCEPTIONS = [
ConnectionError,
Timeout,
]
def send_request(
session: requests.Session,
method: str,
url: str,
retry_exceptions: list[Type[Exception]] | None = None,
retry_fns: list[Callable[[Exception], bool]] | None = None,
n_attempts: int = 15,
**kwargs: Any,
) -> requests.Response:
exceptions_to_catch = retry_exceptions or DEFAULT_RETRY_EXCEPTIONS
retry_condition = retry_if_exception_type(
tuple(exceptions_to_catch)
) | retry_if_exception(is_server_error)
if retry_fns is not None:
for fn in retry_fns:
retry_condition |= retry_if_exception(fn)
@retry(
stop=stop_after_attempt(n_attempts),
wait=wait_exponential(multiplier=1, min=4, max=60),
retry=retry_condition,
reraise=True,
)
def _send_request_with_retry():
response = session.request(method, url, **kwargs)
response.raise_for_status()
return response
return _send_request_with_retry()