{"id":5043,"library":"redo","title":"Redo: Utilities to retry Python callables","description":"Redo is a Python library that provides various mechanisms to add seamless retry functionality to any Python callable. It includes plain functions (redo.retry, redo.retry_async), decorators (redo.retriable, redo.retriable_async), and a context manager (redo.retrying). The current version is 3.0.0, released on July 17, 2024. It enables developers to integrate retry logic with customizable backoff strategies, making code more resilient to transient failures.","status":"active","version":"3.0.0","language":"en","source_language":"en","source_url":"https://github.com/mozilla-releng/redo","tags":["retry","resilience","fault tolerance","backoff","exponential backoff","decorator","async"],"install":[{"cmd":"pip install redo","lang":"bash","label":"Install latest version"}],"dependencies":[],"imports":[{"note":"For functional usage","symbol":"retry","correct":"from redo import retry"},{"note":"For decorator usage","symbol":"retriable","correct":"from redo import retriable"},{"note":"For context manager usage","symbol":"retrying","correct":"from redo import retrying"},{"note":"For asynchronous functional usage","symbol":"retry_async","correct":"from redo import retry_async"},{"note":"For asynchronous decorator usage","symbol":"retriable_async","correct":"from redo import retriable_async"}],"quickstart":{"code":"import random\nimport time\nfrom redo import retriable\n\nMAX_ATTEMPTS = 3\n\n@retriable(\n    attempts=MAX_ATTEMPTS,\n    sleeptime=0.1,  # initial sleep in seconds\n    max_sleeptime=1.0, # max sleep per retry\n    sleepscale=2,   # exponential backoff factor\n    jitter=0.02,    # random +/- seconds to add to sleeptime\n    retry_exceptions=(RuntimeError, ConnectionError) # specify exceptions to retry\n)\ndef flaky_operation(attempt_num: int):\n    # Simulate a network call or I/O operation that might fail\n    if random.random() < 0.7 and attempt_num < MAX_ATTEMPTS: # 70% chance of failure for initial attempts\n        print(f\"Attempt {attempt_num}: Operation failed, retrying...\")\n        raise ConnectionError(\"Failed to connect to service\")\n    print(f\"Attempt {attempt_num}: Operation successful!\")\n    return \"Success\"\n\nif __name__ == \"__main__\":\n    print(\"Starting flaky operation...\")\n    try:\n        result = flaky_operation(attempt_num=1)\n        print(f\"Final result: {result}\")\n    except Exception as e:\n        print(f\"Operation ultimately failed after multiple retries: {e}\")","lang":"python","description":"This quickstart demonstrates using the `@retriable` decorator to automatically retry a potentially flaky function. It configures exponential backoff with jitter and specifies which exceptions should trigger a retry. The `attempt_num` argument in `flaky_operation` is illustrative and would typically be handled internally by `redo`'s retry mechanism counting attempts."},"warnings":[{"fix":"Always explicitly define `retry_exceptions` to a tuple of specific exception types that are expected and can be resolved by retrying, e.g., `retry_exceptions=(ConnectionError, TimeoutError)`.","message":"By default, `redo.retriable` and `redo.retry` catch `Exception` if `retry_exceptions` is not specified. This can mask underlying issues that should not be retried, making debugging difficult.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Carefully test and tune backoff parameters to match the expected retry behavior and system load. Ensure `max_sleeptime` prevents indefinite waits and `attempts` limits overall retry count.","message":"Misconfiguring backoff parameters (`attempts`, `sleeptime`, `max_sleeptime`, `sleepscale`, `jitter`) can lead to excessive delays or a large number of retries, potentially overloading services or causing long wait times.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Always use the `_async` variants (`redo.retry_async`, `redo.retriable_async`) for `async def` callables and the non-`_async` variants for synchronous callables.","message":"Incorrectly mixing synchronous and asynchronous retry mechanisms (e.g., using `redo.retriable` with an `async def` function, or `redo.retriable_async` with a `def` function) will lead to runtime errors or unexpected behavior.","severity":"gotcha","affected_versions":"All versions with async support"}],"env_vars":null,"last_verified":"2026-04-12T00:00:00.000Z","next_check":"2026-07-11T00:00:00.000Z"}