Resilience layer for Python HTTP clients (smart retries, jitter backoff, circuit breaker)
Project description
๐ Resilient HTTP โ Smart, Fault-Tolerant HTTP Client for Python
A modern, production-grade HTTP client wrapper with automatic retries, circuit breakers, jittered backoff, and metrics integration โ all built for reliability under failure.
โจ Features
| โ๏ธ Capability | ๐ก Description |
|---|---|
| ๐ Automatic Retries | Configurable retry logic for transient errors and specific HTTP status codes. |
| โ Circuit Breaker | Opens and closes circuits based on failures to prevent cascading service outages. |
| โฑ Exponential Backoff + Jitter | Prevents thundering-herd retry storms under heavy load. |
| ๐ Metrics Hooks | Customizable metrics sinks for Prometheus, OpenTelemetry, or custom tracking. |
| โก Async + Sync Clients | Full support for both requests and httpx async workflows. |
| ๐ง Configurable Policies | Fine-grained control of retry rules, idempotency, and exception handling. |
| ๐งช 100% Tested | Comprehensive pytest suite with CI and coverage reports. |
๐ฆ Installation
pip install resilient-http
or for the latest development version:
pip install git+https://github.com/pgnikolov/resilient-http.git
๐ Quickstart Examples
๐งฉ Synchronous (Requests)
from resilient_http.resilient_session import ResilientRequestsSession
from resilient_http.retry_policy import RetryPolicy
from resilient_http.circuit_breaker import CircuitBreaker
retry_policy = RetryPolicy(max_attempts=3)
cb = CircuitBreaker(max_failures=2, reset_timeout=10)
session = ResilientRequestsSession(retry_policy=retry_policy, circuit_breaker=cb)
response = session.get("https://httpbin.org/status/503")
print(response.status_code)
Output example:
503 (retrying...)
200
โ๏ธ Asynchronous (HTTPX)
import asyncio
from resilient_http.resilient_async_client import ResilientAsyncClient
from resilient_http.retry_policy import RetryPolicy
async def main():
client = ResilientAsyncClient(retry_policy=RetryPolicy(max_attempts=3))
resp = await client.get("https://httpbin.org/status/503")
print(resp.status_code)
asyncio.run(main())
๐ Configuration
All retry and circuit breaker parameters are configurable:
| Parameter | Type | Default | Description |
|---|---|---|---|
max_attempts |
int |
3 |
Maximum retry attempts per request |
retry_on_status |
tuple[int] |
(500, 502, 503, 504) |
Status codes that trigger retries |
backoff_strategy |
callable |
exponential_backoff |
Backoff function controlling retry delay |
max_failures |
int |
5 |
Failures before circuit breaker opens |
reset_timeout |
float |
30.0 |
Time before circuit transitions to half-open |
Backoff functions can be customized via:
from resilient_http.backoff import exponential_backoff, full_jitter
exp = exponential_backoff(base=2, factor=0.5, max_delay=8)
jittered = full_jitter(exp)
๐งฉ Metrics Integration
You can attach a metrics sink to collect circuit and retry events:
from resilient_http.metrics import MetricsSink
class PrintMetrics(MetricsSink):
def record_event(self, event: str, **data):
print(f"[metrics] {event}: {data}")
session = ResilientRequestsSession(metrics_sink=PrintMetrics())
Output:
[metrics] retry: {'url': 'https://api.service', 'attempt': 1, 'reason': '503'}
[metrics] cb_open: {'key': 'GET https://api.service', 'failures': 5}
๐งฑ Project Structure
resilient-http/
โโโ resilient_http/
โ โโโ __init__.py
โ โโโ backoff.py
โ โโโ circuit_breaker.py
โ โโโ exceptions.py
โ โโโ metrics.py
โ โโโ resilient_async_client.py
โ โโโ resilient_session.py
โ โโโ retry_policy.py
โโโ tests/
โโโ pyproject.toml
โโโ .coveragerc
โโโ README.md
๐งช Running Tests Locally
pytest --cov=resilient_http --cov-report=term-missing
Example output:
22 passed in 1.47s
TOTAL COVERAGE: 82%
๐งฐ Development Setup
git clone https://github.com/pgnikolov/resilient-http.git
cd resilient-http
python -m venv .venv
source .venv/bin/activate # or .venv\Scripts\activate on Windows
pip install -e .[dev]
pytest
๐งฌ Continuous Integration (GitHub Actions)
The CI workflow runs tests on Linux, macOS, and Windows using multiple Python versions.
# .github/workflows/tests.yml
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- run: pip install -e .[dev]
- run: pytest --cov=resilient_http --cov-report=term-missing
๐งพ License
This project is licensed under the terms of the MIT License. See the LICENSE file for details.
๐ค Author
Plamen Nikolov ๐ Oosterhout, Netherlands ๐ผ GitHub: @pgnikolov
โค๏ธ Contributing
Contributions are welcome! Please open issues or submit PRs with improvements or additional features.
๐ Support
If this project helps you build more resilient systems, please โญ the repo on GitHub!
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file resilient_http-1.0.12.tar.gz.
File metadata
- Download URL: resilient_http-1.0.12.tar.gz
- Upload date:
- Size: 15.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
00dd880e5ae3099894f57c031344d4c68866034b51377defb62b8112647bccac
|
|
| MD5 |
6c88071f88b74d8bf1f6dd6b25424d39
|
|
| BLAKE2b-256 |
9761f5791092e62ca273348c59e23b4e8c94c2a9a1ca79ddc653d39119607851
|
File details
Details for the file resilient_http-1.0.12-py3-none-any.whl.
File metadata
- Download URL: resilient_http-1.0.12-py3-none-any.whl
- Upload date:
- Size: 12.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
614c7abdb9e21a9ec8902b044990ea6ee87771b4f571d300a94aae22b75371b5
|
|
| MD5 |
bc24a08935ec3cba135e87917da04755
|
|
| BLAKE2b-256 |
39be99300ac546df48aeeac6dd9efa4732c93c16cccd70e96579512f900738fc
|