HTTPX Retries
HTTPX Retries is a Python library that provides a comprehensive retry layer for HTTPX, addressing common issues with flaky and unreliable APIs. It offers an API surface similar to `urllib3.util.retry.Retry`, making it familiar for users migrating from `requests`. The library supports both synchronous and asynchronous HTTPX clients and is actively maintained with frequent releases.
Warnings
- gotcha HTTPX's built-in `HTTPTransport(retries=...)` only handles connection errors and timeouts, not retries based on HTTP status codes (e.g., 5xx server errors, 429 rate limits). If you need to retry requests based on specific HTTP response status codes, you must use `httpx-retries`.
- breaking There is a similarly named but abandoned package `httpx-retry` (with a hyphen) on PyPI. This package is no longer maintained and explicitly advises migration. Using the wrong package can lead to unmaintained code, security vulnerabilities, or unexpected behavior.
- gotcha Prior to versions 0.4.4 and 0.4.5, `RetryTransport` might not have consistently closed all responses during retry operations, potentially leading to resource leaks, especially with server errors. This was particularly relevant for connections not managed by the client's context manager.
- gotcha In versions prior to 0.3.2, if a `Retry-After` header in a response specified a time in the past, the default backoff mechanism might not have been correctly applied, potentially leading to immediate and aggressive retries. This could overload target services.
Install
-
pip install httpx-retries
Imports
- RetryTransport
from httpx_retries import RetryTransport
- Retry
from httpx_retries import Retry
- RetryPolicy
from httpx_retries import RetryPolicy
Quickstart
import httpx
from httpx_retries import RetryTransport, Retry
def sync_example():
# Basic usage with default retry strategy
with httpx.Client(transport=RetryTransport()) as client:
print("Sync Client (default retries):")
try:
response = client.get("https://httpbin.org/status/503")
print(f" Status: {response.status_code}")
except httpx.HTTPStatusError as e:
print(f" Failed after retries: {e.response.status_code}")
# Custom retry strategy
custom_retry = Retry(total=5, backoff_factor=0.5, statuses_forcelist=[503, 504])
with httpx.Client(transport=RetryTransport(retry=custom_retry)) as client:
print("\nSync Client (custom retries):")
try:
response = client.get("https://httpbin.org/status/503")
print(f" Status: {response.status_code}")
except httpx.HTTPStatusError as e:
print(f" Failed after retries: {e.response.status_code}")
async def async_example():
# Async usage with default retry strategy
async with httpx.AsyncClient(transport=RetryTransport()) as client:
print("\nAsync Client (default retries):")
try:
response = await client.get("https://httpbin.org/status/503")
print(f" Status: {response.status_code}")
except httpx.HTTPStatusError as e:
print(f" Failed after retries: {e.response.status_code}")
# Async usage with custom retry strategy
custom_retry = Retry(total=5, backoff_factor=0.5, statuses_forcelist=[503, 504])
async with httpx.AsyncClient(transport=RetryTransport(retry=custom_retry)) as client:
print("\nAsync Client (custom retries):")
try:
response = await client.get("https://httpbin.org/status/503")
print(f" Status: {response.status_code}")
except httpx.HTTPStatusError as e:
print(f" Failed after retries: {e.response.status_code}")
if __name__ == "__main__":
sync_example()
import asyncio
asyncio.run(async_example())