{"id":2786,"library":"stamina","title":"Stamina: Production-Grade Retries","description":"Stamina is a Python library that provides production-grade retries made easy, acting as an opinionated wrapper around Tenacity. It ensures resilient systems by handling transient failures with sensible defaults like exponential backoff with jitter, configurable exception handling, and automatic async support. It releases regularly, typically every few months, and is designed to minimize potential for misuse.","status":"active","version":"25.2.0","language":"en","source_language":"en","source_url":"https://github.com/hynek/stamina","tags":["retry","resilience","error handling","backoff","async","concurrency","fault tolerance"],"install":[{"cmd":"pip install stamina","lang":"bash","label":"Install latest version"},{"cmd":"pip install stamina httpx","lang":"bash","label":"Install with common dependencies for examples"}],"dependencies":[{"reason":"Requires Python 3.10 or newer.","package":"python","optional":false},{"reason":"Commonly used in examples for HTTP requests; not a core dependency but useful for quickstart.","package":"httpx","optional":true},{"reason":"Optional for Prometheus instrumentation of retries.","package":"prometheus-client","optional":true},{"reason":"Optional for structlog instrumentation of retries.","package":"structlog","optional":true}],"imports":[{"note":"Main decorator for retrying functions.","symbol":"retry","correct":"from stamina import retry"},{"note":"For retrying arbitrary code blocks using a context manager.","symbol":"retry_context","correct":"from stamina import retry_context"},{"note":"For activating/deactivating test mode and controlling retry behavior during tests.","symbol":"set_testing","correct":"from stamina import set_testing"},{"note":"For retrying single function/method calls without decorating.","symbol":"RetryingCaller","correct":"from stamina import RetryingCaller"}],"quickstart":{"code":"import httpx\nimport stamina\nimport os\n\n@stamina.retry(on=httpx.HTTPStatusError, attempts=3, timeout=5)\ndef fetch_url_with_retry(url: str) -> str:\n    try:\n        response = httpx.get(url, timeout=1)\n        response.raise_for_status() # Raises HTTPStatusError for 4xx/5xx responses\n        return f\"Successfully fetched: {response.status_code}\"\n    except httpx.HTTPStatusError as e:\n        # Example: only retry on 5xx errors\n        if e.response.status_code >= 500:\n            print(f\"Retrying on {e.response.status_code} for {url}...\")\n            raise\n        else:\n            print(f\"Not retrying on {e.response.status_code} for {url}.\")\n            raise\n    except httpx.RequestError as e:\n        print(f\"Request error for {url}: {e}, retrying...\")\n        raise\n\n# Example usage:\ntry:\n    # This URL will fail with 500 and retry\n    print(fetch_url_with_retry(\"https://httpbin.org/status/500\"))\nexcept (httpx.HTTPStatusError, httpx.RequestError) as e:\n    print(f\"Final failure after retries for 500: {e}\")\n\ntry:\n    # This URL will fail with 404 and not retry (due to the if e.response.status_code >= 500 check)\n    print(fetch_url_with_retry(\"https://httpbin.org/status/404\"))\nexcept (httpx.HTTPStatusError, httpx.RequestError) as e:\n    print(f\"Final failure for 404 (not retried): {e}\")\n\ntry:\n    # This URL will succeed\n    print(fetch_url_with_retry(\"https://httpbin.org/status/200\"))\nexcept (httpx.HTTPStatusError, httpx.RequestError) as e:\n    print(f\"Unexpected failure for 200: {e}\")\n","lang":"python","description":"This quickstart demonstrates using the `@stamina.retry` decorator with `httpx` to handle transient HTTP errors. It configures retries for `httpx.HTTPStatusError` but includes a custom check to only retry on 5xx status codes, explicitly not retrying on 4xx client errors, and limits attempts and total timeout."},"warnings":[{"fix":"Upgrade your Python environment to 3.10 or newer.","message":"Stamina versions 25.2.0 and newer require Python 3.10 or higher. Projects on older Python versions (3.8, 3.9) must update their Python environment before upgrading to the latest stamina versions.","severity":"breaking","affected_versions":">=25.2.0"},{"fix":"Always explicitly specify the `on` parameter, e.g., `@stamina.retry(on=httpx.HTTPError)` or `on=(ConnectionError, TimeoutError)`.","message":"The `on` parameter in `stamina.retry()` is mandatory and has no default value. Unlike some other retry libraries, `stamina` explicitly forces you to define which exceptions trigger a retry, preventing accidental retries on non-transient errors (e.g., `Exception` generally).","severity":"gotcha","affected_versions":"All versions"},{"fix":"Wrap your test code that modifies retry behavior in a `with stamina.set_testing(...)` block.","message":"When testing retry logic, `stamina.set_testing()` is now recommended to be used as a context manager. While older global activation might still work, using it as a context manager ensures proper cleanup and isolated test environments, preventing test interference.","severity":"gotcha","affected_versions":">=25.1.0"},{"fix":"Be aware that relying heavily on generator function retries might be subject to future changes. Monitor release notes for updates.","message":"Support for retrying generator functions and async generator functions (introduced in 25.2.0) is provisional and may be removed in future versions if it causes unforeseen complexities.","severity":"gotcha","affected_versions":">=25.2.0"},{"fix":"Ensure you are using `stamina` version 24.1.0 or newer to guarantee correct deactivation behavior. For testing, also consider using `stamina.set_testing()` as a context manager.","message":"Versions prior to 24.1.0 contained a bug where deactivating `stamina` globally (e.g., for testing) might not have worked correctly, leading to decorated blocks being retried even when deactivated.","severity":"gotcha","affected_versions":"<24.1.0"}],"env_vars":null,"last_verified":"2026-04-10T00:00:00.000Z","next_check":"2026-07-09T00:00:00.000Z"}