Async function retry decorator Args: config: Retry configuration object, uses default config if None on_retry: Callback function on retry, receives exception and current attempt number Returns: Decorator function Example: ```python @async_retry(
(
config: RetryConfig | None = None,
on_retry: Callable[[Exception, int], None] | None = None,
)
| 71 | |
| 72 | |
| 73 | def async_retry( |
| 74 | config: RetryConfig | None = None, |
| 75 | on_retry: Callable[[Exception, int], None] | None = None, |
| 76 | ) -> Callable: |
| 77 | """Async function retry decorator |
| 78 | |
| 79 | Args: |
| 80 | config: Retry configuration object, uses default config if None |
| 81 | on_retry: Callback function on retry, receives exception and current attempt number |
| 82 | |
| 83 | Returns: |
| 84 | Decorator function |
| 85 | |
| 86 | Example: |
| 87 | ```python |
| 88 | @async_retry(RetryConfig(max_retries=3, initial_delay=1.0)) |
| 89 | async def call_api(): |
| 90 | # API call code |
| 91 | pass |
| 92 | ``` |
| 93 | """ |
| 94 | if config is None: |
| 95 | config = RetryConfig() |
| 96 | |
| 97 | def decorator(func: Callable[..., Any]) -> Callable[..., Any]: |
| 98 | @functools.wraps(func) |
| 99 | async def wrapper(*args: Any, **kwargs: Any) -> Any: |
| 100 | last_exception: Exception | None = None |
| 101 | |
| 102 | for attempt in range(config.max_retries + 1): |
| 103 | try: |
| 104 | # Try to execute function |
| 105 | return await func(*args, **kwargs) |
| 106 | |
| 107 | except config.retryable_exceptions as e: |
| 108 | last_exception = e |
| 109 | |
| 110 | # If this is the last attempt, don't retry |
| 111 | if attempt >= config.max_retries: |
| 112 | logger.error(f"Function {func.__name__} retry failed, reached maximum retry count {config.max_retries}") |
| 113 | raise RetryExhaustedError(e, attempt + 1) |
| 114 | |
| 115 | # Calculate delay time |
| 116 | delay = config.calculate_delay(attempt) |
| 117 | |
| 118 | # Log |
| 119 | logger.warning( |
| 120 | f"Function {func.__name__} call {attempt + 1} failed: {str(e)}, " |
| 121 | f"retrying attempt {attempt + 2} after {delay:.2f} seconds" |
| 122 | ) |
| 123 | |
| 124 | # Call callback function |
| 125 | if on_retry: |
| 126 | on_retry(e, attempt + 1) |
| 127 | |
| 128 | # Wait before retry |
| 129 | await asyncio.sleep(delay) |
| 130 |
no test coverage detected