{"id":9445,"library":"aioretry","title":"Asyncio Retry Utility","description":"aioretry is an asyncio utility for Python 3.7+ that provides flexible retry mechanisms for asynchronous operations. It supports various retry policies, including fixed delay, exponential backoff, and custom strategies, handling transient failures in async code gracefully. The current version is 6.3.1, and it maintains an 'active' release cadence with regular updates.","status":"active","version":"6.3.1","language":"en","source_language":"en","source_url":"https://github.com/kaelzhang/python-aioretry","tags":["async","retry","asyncio","error-handling","concurrency"],"install":[{"cmd":"pip install aioretry","lang":"bash","label":"Install latest version"}],"dependencies":[],"imports":[{"symbol":"retry","correct":"from aioretry import retry"},{"symbol":"RetryInfo","correct":"from aioretry import RetryInfo"},{"symbol":"RetryPolicyStrategy","correct":"from aioretry import RetryPolicyStrategy"}],"quickstart":{"code":"import asyncio\nfrom aioretry import retry, RetryInfo, RetryPolicyStrategy\n\nfail_count = 0\n\nasync def my_retry_policy(info: RetryInfo) -> RetryPolicyStrategy:\n    \"\"\"Retry up to 3 times, with increasing delay.\"\"\"\n    # (should_give_up, delay_in_seconds)\n    return info.fails >= 3, info.fails * 0.5\n\n@retry(policy=my_retry_policy)\nasync def flaky_async_call():\n    global fail_count\n    fail_count += 1\n    print(f\"Attempt {fail_count}: Making a flaky call...\")\n    if fail_count < 3: # Succeed on the 3rd attempt\n        raise ConnectionError(\"Simulated network issue\")\n    print(f\"Attempt {fail_count}: Call succeeded!\")\n    return \"Data Fetched\"\n\nasync def main():\n    print(\"Starting main program...\")\n    try:\n        result = await flaky_async_call()\n        print(f\"Final Result: {result}\")\n    except Exception as e:\n        print(f\"Operation failed after retries: {e}\")\n    print(\"Program finished.\")\n\nif __name__ == \"__main__\":\n    asyncio.run(main())","lang":"python","description":"This quickstart demonstrates using the `@retry` decorator with a custom asynchronous retry policy. The `flaky_async_call` function simulates transient failures, and `my_retry_policy` specifies when to give up and how long to delay between attempts."},"warnings":[{"fix":"Update your retry policies to use `info.since` as a float directly (e.g., `time.monotonic() - info.since`) instead of `datetime` methods like `.total_seconds()`.","message":"The type of `RetryInfo::since` changed from `datetime` to `float` (from `time.monotonic()`) in version 6.0.0. This improves precision for measuring intervals but breaks code expecting `datetime` methods.","severity":"breaking","affected_versions":">=6.0.0"},{"fix":"Upgrade `aioretry` to `6.2.0` or higher if you need to use `async def` for your retry policies. For older versions, policies must be synchronous functions.","message":"Asynchronous retry policies (e.g., `async def custom_policy(...)`) were introduced in version 6.2.0. If you define an async policy, ensure your `aioretry` version is 6.2.0 or newer.","severity":"gotcha","affected_versions":"<6.2.0"},{"fix":"Ensure your custom policy function (sync or async) consistently returns a tuple of exactly two elements: a boolean indicating whether to stop retrying, and a float for the delay before the next attempt.","message":"Custom retry policies must return a tuple `(should_give_up: bool, delay_in_seconds: float)`. Returning fewer or more values, or values of incorrect types, will lead to runtime errors.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-17T00:00:00.000Z","next_check":"2026-07-16T00:00:00.000Z","problems":[{"fix":"Replace `(datetime.now() - info.since).total_seconds()` or similar with `time.monotonic() - info.since` to calculate elapsed time, as `info.since` is already a `float`.","cause":"Attempting to call `.total_seconds()` on `RetryInfo.since` after `aioretry` 6.0.0. `since` is now a `float` (monotonic time), not a `datetime` object.","error":"AttributeError: 'float' object has no attribute 'total_seconds'"},{"fix":"If you intend to use an `async def` retry policy, upgrade `aioretry` to version 6.2.0 or newer. If your policy doesn't require `await`, define it as a regular `def` function.","cause":"This typically occurs when trying to use an `async def` retry policy function with `aioretry` versions older than 6.2.0, or if your policy function is incorrectly defined as `async` when it should be sync (or vice versa in specific contexts).","error":"TypeError: object NoneType can't be used in 'await' expression OR TypeError: 'function' object is not awaitable"},{"fix":"Modify your custom retry policy to explicitly return a 2-element tuple: the first element as a boolean (`True` to give up, `False` to retry), and the second as a float for the delay in seconds. Example: `return info.fails > MAX_ATTEMPTS, info.fails * 0.1`.","cause":"A custom retry policy function returned a single boolean or an incorrect structure instead of the required `(should_give_up: bool, delay_in_seconds: float)` tuple.","error":"ValueError: not enough values to unpack (expected 2, got 1) OR TypeError: 'bool' object is not iterable"}]}