agent_search_gateway.retry
Generic configurable exponential retry engine.
1"""Generic configurable exponential retry engine.""" 2 3import asyncio 4from collections.abc import Awaitable, Callable 5from contextlib import suppress 6from typing import TypeVar 7 8from .models import RetryPolicy 9 10T = TypeVar("T") 11BeforeAttempt = Callable[[int], None] 12OnRetry = Callable[[int, BaseException, float], None] 13 14 15async def retry_async( 16 policy: RetryPolicy, 17 operation: Callable[[], Awaitable[T]], 18 *, 19 is_retryable: Callable[[BaseException], bool], 20 sleep: Callable[[float], Awaitable[None]] = asyncio.sleep, 21 before_attempt: BeforeAttempt | None = None, 22 on_retry: OnRetry | None = None, 23) -> T: 24 for attempt in range(1, policy.max_attempts + 1): 25 if before_attempt is not None: 26 with suppress(Exception): 27 before_attempt(attempt) 28 try: 29 return await operation() 30 except BaseException as exc: 31 if isinstance(exc, asyncio.CancelledError): 32 raise 33 if attempt == policy.max_attempts or not is_retryable(exc): 34 raise 35 delay = min( 36 policy.base_delay_seconds * (2 ** (attempt - 1)), 37 policy.max_delay_seconds, 38 ) 39 if on_retry is not None: 40 with suppress(Exception): 41 on_retry(attempt, exc, delay) 42 await sleep(delay) 43 raise RuntimeError("retry loop exhausted unexpectedly")
BeforeAttempt =
collections.abc.Callable[[int], None]
OnRetry =
collections.abc.Callable[[int, BaseException, float], None]
async def
retry_async( policy: agent_search_gateway.models.RetryPolicy, operation: Callable[[], Awaitable[~T]], *, is_retryable: Callable[[BaseException], bool], sleep: Callable[[float], Awaitable[None]] = <function sleep>, before_attempt: Callable[[int], None] | None = None, on_retry: Callable[[int, BaseException, float], None] | None = None) -> ~T:
16async def retry_async( 17 policy: RetryPolicy, 18 operation: Callable[[], Awaitable[T]], 19 *, 20 is_retryable: Callable[[BaseException], bool], 21 sleep: Callable[[float], Awaitable[None]] = asyncio.sleep, 22 before_attempt: BeforeAttempt | None = None, 23 on_retry: OnRetry | None = None, 24) -> T: 25 for attempt in range(1, policy.max_attempts + 1): 26 if before_attempt is not None: 27 with suppress(Exception): 28 before_attempt(attempt) 29 try: 30 return await operation() 31 except BaseException as exc: 32 if isinstance(exc, asyncio.CancelledError): 33 raise 34 if attempt == policy.max_attempts or not is_retryable(exc): 35 raise 36 delay = min( 37 policy.base_delay_seconds * (2 ** (attempt - 1)), 38 policy.max_delay_seconds, 39 ) 40 if on_retry is not None: 41 with suppress(Exception): 42 on_retry(attempt, exc, delay) 43 await sleep(delay) 44 raise RuntimeError("retry loop exhausted unexpectedly")