### Install aiohttp-retry Source: https://context7.com/inyutin/aiohttp_retry/llms.txt Install the library using pip. ```bash pip install aiohttp-retry ``` -------------------------------- ### Implementing Request Start Trace Logging Source: https://github.com/inyutin/aiohttp_retry/blob/master/README.md Demonstrates how to use the trace mechanic to log messages when a request starts, specifically logging a warning on the last attempt. This requires setting up a logging handler and a trace configuration. ```python import logging import sys from types import SimpleNamespace from aiohttp import ClientSession, TraceConfig, TraceRequestStartParams from aiohttp_retry import RetryClient, ExponentialRetry handler = logging.StreamHandler(sys.stdout) logging.basicConfig(handlers=[handler]) logger = logging.getLogger(__name__) retry_options = ExponentialRetry(attempts=2) async def on_request_start( session: ClientSession, trace_config_ctx: SimpleNamespace, params: TraceRequestStartParams, ) -> None: current_attempt = trace_config_ctx.trace_request_ctx['current_attempt'] if retry_options.attempts <= current_attempt: logger.warning('Wow! We are in last attempt') async def main(): trace_config = TraceConfig() trace_config.on_request_start.append(on_request_start) retry_client = RetryClient(retry_options=retry_options, trace_configs=[trace_config]) response = await retry_client.get('https://httpstat.us/503', ssl=False) print(response.status) await retry_client.close() ``` -------------------------------- ### Basic RetryClient Usage with ExponentialRetry Source: https://github.com/inyutin/aiohttp_retry/blob/master/README.md Demonstrates initializing RetryClient with ExponentialRetry and making a GET request. Set raise_for_status=False to prevent exceptions for non-2xx status codes. ```python from aiohttp_retry import RetryClient, ExponentialRetry async def main(): retry_options = ExponentialRetry(attempts=1) retry_client = RetryClient(raise_for_status=False, retry_options=retry_options) async with retry_client.get('https://ya.ru') as response: print(response.status) await retry_client.close() ``` -------------------------------- ### RetryClient Usage with RandomRetry Source: https://github.com/inyutin/aiohttp_retry/blob/master/README.md Illustrates using RetryClient with the RandomRetry strategy. Note that this example uses a relative URL '/ping', which might require specific server configuration. ```python from aiohttp_retry import RetryClient, RandomRetry async def main(): retry_options = RandomRetry(attempts=1) retry_client = RetryClient(raise_for_status=False, retry_options=retry_options) response = await retry_client.get('/ping') print(response.status) await retry_client.close() ``` -------------------------------- ### Rotate URLs Between Retries Using Shorthand Source: https://context7.com/inyutin/aiohttp_retry/llms.txt Pass a list or tuple of URLs directly to methods like get(), post(), etc., as a shorthand for rotating through URLs on retries. The last URL is reused if the list is exhausted before attempts. ```python import asyncio from aiohttp_retry import RetryClient, ExponentialRetry async def main(): async with RetryClient(retry_options=ExponentialRetry(attempts=3)) as client: async with client.get( url=[ "https://httpbin.org/status/500", # attempt 1 — fails "https://httpbin.org/status/200", # attempt 2 — succeeds ] ) as response: print(f"Status: {response.status}") # 200 asyncio.run(main()) ``` -------------------------------- ### RetryClient as Async Context Manager Source: https://github.com/inyutin/aiohttp_retry/blob/master/README.md Demonstrates the simplest way to use RetryClient by leveraging its async context manager capabilities. This automatically handles client initialization and closing. ```python from aiohttp_retry import RetryClient async def main(): async with RetryClient() as client: async with client.get('https://ya.ru') as response: print(response.status) ``` -------------------------------- ### Making Multiple Requests with Different Parameters Source: https://github.com/inyutin/aiohttp_retry/blob/master/README.md Shows how to send a sequence of requests with varying parameters, including headers, using the `requests` method and `RequestParams`. The `response` object will contain the result of the last request in the sequence. ```python from aiohttp_retry import RetryClient, RequestParams, ExponentialRetry async def main(): retry_client = RetryClient(raise_for_status=False) async with retry_client.requests( params_list=[ RequestParams( method='GET', url='https://ya.ru', ), RequestParams( method='GET', url='https://ya.ru', headers={'some_header': 'some_value'}, ), ] ) as response: print(response.status) await retry_client.close() ``` -------------------------------- ### RetryClient with Existing ClientSession Source: https://github.com/inyutin/aiohttp_retry/blob/master/README.md Shows how to integrate RetryClient with an existing aiohttp ClientSession. Ensure the underlying ClientSession is closed after use. ```python from aiohttp import ClientSession from aiohttp_retry import RetryClient async def main(): client_session = ClientSession() retry_client = RetryClient(client_session=client_session) async with retry_client.get('https://ya.ru') as response: print(response.status) await client_session.close() ``` -------------------------------- ### ListRetry Strategy Configuration Source: https://context7.com/inyutin/aiohttp_retry/llms.txt Use a predefined list of timeouts for deterministic retry timing. The number of attempts is determined by the length of the timeout list. ```python import asyncio from aiohttp_retry import RetryClient, ListRetry async def main(): # 3 attempts; waits 0 s, then 1 s, then 5 s before each successive retry retry_options = ListRetry(timeouts=[0.0, 1.0, 5.0]) async with RetryClient(retry_options=retry_options) as client: async with client.get("https://httpbin.org/status/503") as response: print(f"Final status: {response.status}") asyncio.run(main()) ``` -------------------------------- ### Wrapping an Existing ClientSession with RetryClient Source: https://context7.com/inyutin/aiohttp_retry/llms.txt Wrap a pre-configured aiohttp.ClientSession to reuse connection pools and settings. The user is responsible for closing the session. ```python import asyncio import aiohttp from aiohttp_retry import RetryClient, ExponentialRetry async def main(): async with aiohttp.ClientSession(headers={"User-Agent": "my-app/1.0"}) as session: retry_client = RetryClient( client_session=session, retry_options=ExponentialRetry(attempts=4), ) async with retry_client.get("https://httpbin.org/get") as response: data = await response.json() print(data["headers"]["User-Agent"]) # my-app/1.0 asyncio.run(main()) ``` -------------------------------- ### Define RetryOptions Configuration Source: https://github.com/inyutin/aiohttp_retry/blob/master/README.md Configure retry attempts, statuses, exceptions, and server error handling. Use this to customize retry behavior for requests. ```python class RetryOptionsBase: def __init__( self, attempts: int = 3, # How many times we should retry statuses: Iterable[int] | None = None, # On which statuses we should retry exceptions: Iterable[type[Exception]] | None = None, # On which exceptions we should retry, by default on all retry_all_server_errors: bool = True, # If should retry all 500 errors or not # a callback that will run on response to decide if retry evaluate_response_callback: EvaluateResponseCallbackType | None = None, ): ... @abc.abstractmethod def get_timeout(self, attempt: int, response: Optional[Response] = None) -> float: raise NotImplementedError ``` -------------------------------- ### ExponentialRetry Strategy Configuration Source: https://context7.com/inyutin/aiohttp_retry/llms.txt Configure exponential backoff with custom timeouts, factors, and specific HTTP status codes for retries. Retries all server errors if enabled. ```python import asyncio from aiohttp_retry import RetryClient, ExponentialRetry async def main(): retry_options = ExponentialRetry( attempts=5, start_timeout=0.1, # first wait: 0.1 * 2^1 = 0.2 s max_timeout=10.0, # never wait more than 10 s factor=2.0, statuses={429, 503}, # also retry on rate-limit and service-unavailable retry_all_server_errors=True, ) async with RetryClient(retry_options=retry_options) as client: async with client.get("https://httpbin.org/status/503") as response: print(f"Final status: {response.status}") asyncio.run(main()) ``` -------------------------------- ### Define RequestParams for Multiple Retries Source: https://github.com/inyutin/aiohttp_retry/blob/master/README.md Structure to define parameters for ClientSession.request when making requests with varying parameters across retries. Includes method, URL, headers, trace context, and additional keyword arguments. ```python @dataclass class RequestParams: method: str url: _RAW_URL_TYPE headers: dict[str, Any] | None = None trace_request_ctx: dict[str, Any] | None = None kwargs: dict[str, Any] | None = None ``` -------------------------------- ### RandomRetry Strategy Configuration Source: https://context7.com/inyutin/aiohttp_retry/llms.txt Implement random backoff between min and max timeouts for retries. Useful for spreading load. Configures specific HTTP status codes for retries. ```python import asyncio from aiohttp_retry import RetryClient, RandomRetry async def main(): retry_options = RandomRetry( attempts=4, min_timeout=0.5, max_timeout=5.0, statuses={500, 502, 503, 504}, ) async with RetryClient(retry_options=retry_options) as client: async with client.post( "https://httpbin.org/status/500", json={"key": "value"}, ) as response: print(f"Final status: {response.status}") asyncio.run(main()) ``` -------------------------------- ### RetryClient Request with Multiple URLs Source: https://github.com/inyutin/aiohttp_retry/blob/master/README.md Use this to specify a list of URLs for retrying requests. The client will cycle through the URLs for each attempt. If fewer URLs are provided than the number of attempts, the last URL will be used for subsequent retries. ```python from aiohttp_retry import RetryClient retry_client = RetryClient() async with retry_client.get(url=['/internal_error', '/ping']) as response: text = await response.text() assert response.status == 200 assert text == 'Ok!' await retry_client.close() ``` -------------------------------- ### JitterRetry Strategy Source: https://context7.com/inyutin/aiohttp_retry/llms.txt Implements exponential backoff with random jitter. It adds a random interval to the base exponential wait time to further decorrelate retry storms across concurrent clients. ```python import asyncio from aiohttp_retry import RetryClient, JitterRetry async def main(): retry_options = JitterRetry( attempts=4, start_timeout=0.1, max_timeout=30.0, factor=2.0, random_interval_size=1.5, ) async with RetryClient(retry_options=retry_options) as client: async with client.get("https://httpbin.org/status/503") as response: print(f"Final status: {response.status}") asyncio.run(main()) ``` -------------------------------- ### FibonacciRetry Strategy Source: https://context7.com/inyutin/aiohttp_retry/llms.txt Uses a Fibonacci sequence for wait times, multiplied by a factor and capped at a maximum timeout. This strategy provides a gentler back-pressure than exponential backoff. ```python import asyncio from aiohttp_retry import RetryClient, FibonacciRetry async def main(): retry_options = FibonacciRetry( attempts=5, multiplier=0.5, # waits: 1, 1, 1.5, 2, 2.5 ... (capped at max_timeout) max_timeout=10.0, ) async with RetryClient(retry_options=retry_options) as client: async with client.get("https://httpbin.org/status/503") as response: print(f"Final status: {response.status}") asyncio.run(main()) ``` -------------------------------- ### Per-Request Retry Option Override Source: https://context7.com/inyutin/aiohttp_retry/llms.txt Demonstrates how to override client-level retry options for a specific request. Options passed directly to the request method take precedence over client defaults. ```python import asyncio from aiohttp_retry import RetryClient, ExponentialRetry async def main(): # Client default: 2 attempts async with RetryClient(retry_options=ExponentialRetry(attempts=2)) as client: # This specific call uses 5 attempts instead per_request_opts = ExponentialRetry(attempts=5, statuses={404}) async with client.get( "https://httpbin.org/status/404", retry_options=per_request_opts, raise_for_status=False, ) as response: print(f"Status: {response.status}") # 404, retried 5 times asyncio.run(main()) ``` -------------------------------- ### Log Retry Attempts Using Trace Context Source: https://context7.com/inyutin/aiohttp_retry/llms.txt Leverage aiohttp's TraceConfig to hook into request lifecycle events. RetryClient injects `current_attempt` into `trace_request_ctx` for logging or monitoring retry progress. ```python import asyncio import logging from types import SimpleNamespace from aiohttp import ClientSession, TraceConfig, TraceRequestStartParams from aiohttp_retry import RetryClient, ExponentialRetry logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) retry_options = ExponentialRetry(attempts=3) async def on_request_start( session: ClientSession, trace_config_ctx: SimpleNamespace, params: TraceRequestStartParams, ) -> None: attempt = trace_config_ctx.trace_request_ctx["current_attempt"] logger.info("Starting attempt %d/%d → %s", attempt, retry_options.attempts, params.url) if attempt == retry_options.attempts: logger.warning("This is the LAST attempt for %s", params.url) async def main(): trace_config = TraceConfig() trace_config.on_request_start.append(on_request_start) async with RetryClient( retry_options=retry_options, trace_configs=[trace_config], ) as client: async with client.get("https://httpbin.org/status/503") as response: print(f"Final status: {response.status}") asyncio.run(main()) ``` -------------------------------- ### Custom RetryOptionsBase Subclass for Retry-After Header Source: https://context7.com/inyutin/aiohttp_retry/llms.txt Subclass RetryOptionsBase to implement custom wait logic, such as honoring the 'Retry-After' header from server responses. Falls back to a default wait time if the header is missing or invalid. ```python import asyncio from aiohttp import ClientResponse from aiohttp_retry import RetryClient from aiohttp_retry.retry_options import RetryOptionsBase class RetryAfterRetry(RetryOptionsBase): """Honor the server's Retry-After header; fall back to `default_wait` seconds.""" def __init__(self, attempts: int = 3, default_wait: float = 1.0) -> None: super().__init__(attempts=attempts) self._default_wait = default_wait def get_timeout(self, attempt: int, response: ClientResponse | None = None) -> float: if response is not None: retry_after = response.headers.get("Retry-After") if retry_after is not None: try: return float(retry_after) except ValueError: pass return self._default_wait * attempt async def main(): async with RetryClient(retry_options=RetryAfterRetry(attempts=4, default_wait=2.0)) as client: async with client.get("https://httpbin.org/status/429") as response: print(f"Final status: {response.status}") asyncio.run(main()) ``` -------------------------------- ### ClientType Union Type for Flexible Function Signatures Source: https://context7.com/inyutin/aiohttp_retry/llms.txt Utilize the ClientType union type for function signatures that accept either a plain aiohttp ClientSession or a RetryClient. This allows shared utility functions to work seamlessly with both. ```python from aiohttp import ClientSession from aiohttp_retry import RetryClient, ExponentialRetry from aiohttp_retry.types import ClientType async def fetch(client: ClientType, url: str) -> int: async with client.get(url) as response: # type: ignore[union-attr] return response.status async def main(): # Works with a plain ClientSession async with ClientSession() as plain_client: status = await fetch(plain_client, "https://httpbin.org/get") print(f"Plain session status: {status}") # Works with a RetryClient async with RetryClient(retry_options=ExponentialRetry(attempts=3)) as retry_client: status = await fetch(retry_client, "https://httpbin.org/get") print(f"Retry client status: {status}") import asyncio asyncio.run(main()) ``` -------------------------------- ### raise_for_status for Automatic Exceptions Source: https://context7.com/inyutin/aiohttp_retry/llms.txt When `raise_for_status=True`, an `aiohttp.ClientResponseError` is raised on the final non-retryable error response. This can be combined with `exceptions` to retry on `ClientResponseError`. ```python import asyncio from aiohttp import ClientResponseError from aiohttp_retry import RetryClient, ExponentialRetry async def main(): retry_options = ExponentialRetry( attempts=3, statuses={503}, exceptions={ClientResponseError}, ) async with RetryClient( retry_options=retry_options, raise_for_status=True, ) as client: try: async with client.get("https://httpbin.org/status/503") as response: print(response.status) except ClientResponseError as exc: print(f"Failed after retries: HTTP {exc.status}") # Failed after retries: HTTP 503 asyncio.run(main()) ``` -------------------------------- ### Change Request Parameters Between Retries Source: https://context7.com/inyutin/aiohttp_retry/llms.txt Use a list of RequestParams to specify different URLs, methods, or headers for each retry attempt. If the list is shorter than the number of attempts, the last entry is reused. ```python import asyncio from aiohttp_retry import RetryClient, ExponentialRetry from aiohttp_retry.client import RequestParams async def main(): async with RetryClient(retry_options=ExponentialRetry(attempts=3)) as client: # First try primary endpoint; on failure fall back to secondary async with client.requests( params_list=[ RequestParams( method="GET", url="https://primary.example.com/api/data", ), RequestParams( method="GET", url="https://secondary.example.com/api/data", headers={"X-Fallback": "true"}, ), ], retry_options=ExponentialRetry(attempts=2), ) as response: print(f"Status: {response.status}") print(f"URL: {response.url}") asyncio.run(main()) ``` -------------------------------- ### Retry Specific HTTP Methods Only Source: https://context7.com/inyutin/aiohttp_retry/llms.txt Use the `methods` parameter in RetryOptions to restrict retries to a subset of HTTP methods, preventing unintended retries on non-idempotent operations like POST or PUT. ```python import asyncio from aiohttp_retry import RetryClient, ExponentialRetry async def main(): # Only retry GET and HEAD; never retry POST/PUT/DELETE retry_options = ExponentialRetry( attempts=4, methods={"GET", "HEAD"}, ) async with RetryClient(retry_options=retry_options) as client: # This POST will NOT be retried even on 500 async with client.post( "https://httpbin.org/status/500", json={"order_id": 42}, retry_options=ExponentialRetry(attempts=4, methods={"GET"}), ) as response: print(f"POST status (no retry): {response.status}") # 500 after 1 attempt asyncio.run(main()) ``` -------------------------------- ### Custom Retry Condition with evaluate_response_callback Source: https://context7.com/inyutin/aiohttp_retry/llms.txt Allows defining a custom asynchronous callback function to control retry logic at the response level. The callback should return `True` to skip retry or `False` to trigger a retry. ```python import asyncio from aiohttp import ClientResponse from aiohttp_retry import RetryClient, ExponentialRetry async def is_valid_json(response: ClientResponse) -> bool: """Retry if response body is not valid JSON.""" try: await response.json() return True # valid — do NOT retry except Exception: return False # invalid — retry async def main(): retry_options = ExponentialRetry( attempts=5, evaluate_response_callback=is_valid_json, ) async with RetryClient(retry_options=retry_options) as client: async with client.get("https://httpbin.org/json") as response: data = await response.json() print(data) asyncio.run(main()) ``` -------------------------------- ### RetryClient requests method signature Source: https://github.com/inyutin/aiohttp_retry/blob/master/README.md Signature for the requests method, which allows making multiple requests with different parameters. It accepts a list of RequestParams and optional retry options. ```python def requests( self, params_list: list[RequestParams], retry_options: RetryOptionsBase | None = None, raise_for_status: bool | None = None, ) -> _RequestContext: ``` -------------------------------- ### ClientType Union Type Source: https://github.com/inyutin/aiohttp_retry/blob/master/README.md A type alias representing either a ClientSession or a RetryClient. Useful for type hinting when a function can accept either. ```python ClientType = Union[ClientSession, RetryClient] ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.