pyresilience¶
Unified resilience patterns for Python — retry, circuit breaker, timeout, fallback, bulkhead, rate limiter, and cache in one decorator.
Instead of stacking multiple decorators from different libraries, define your entire resilience policy in a single @resilient() call.
Why pyresilience?¶
Existing Python libraries solve individual problems well:
- tenacity — retry only
- pybreaker — circuit breaker only
- wrapt_timeout_decorator — timeout only
But combining them means stacking decorators, managing separate configs, and losing visibility across patterns. pyresilience unifies everything.
All Seven Patterns¶
| Module | Config | Description |
|---|---|---|
| Circuit Breaker | CircuitBreakerConfig |
Prevents calls to failing services |
| Retry | RetryConfig |
Retries failed calls with backoff |
| Bulkhead | BulkheadConfig |
Limits concurrent executions |
| Timeout | TimeoutConfig |
Enforces per-call time limits |
| Rate Limiter | RateLimiterConfig |
Limits call rate per time window |
| Cache | CacheConfig |
Caches successful results |
| Fallback | FallbackConfig |
Graceful degradation on failure |
At a Glance¶
import requests
from pyresilience import resilient, RetryConfig, TimeoutConfig, CircuitBreakerConfig
@resilient(
retry=RetryConfig(max_attempts=3, delay=1.0),
timeout=TimeoutConfig(seconds=10),
circuit_breaker=CircuitBreakerConfig(failure_threshold=5),
)
def call_payment_api(amount: float) -> dict:
return requests.post("/charge", json={"amount": amount}).json()
This single decorator:
- Retries up to 3 times with exponential backoff
- Times out each attempt after 10 seconds
- Opens the circuit after 5 consecutive failures, blocking further calls until recovery
All patterns work together, with a unified event system for observability.
Key Features¶
- All 7 resilience patterns in one library
- One decorator —
@resilient()combines everything - Zero dependencies — pure Python stdlib
- Full async support — auto-detects sync vs async
- Type-safe — strict mypy compatible,
py.typedmarker - Sliding window circuit breaker — failure rate % threshold, slow call detection
- Retry on result — retry based on return values, not just exceptions
- Retry budget — shared token pool limits cascading retries across callers
- Per-attempt timeout — per-call or total deadline timeout modes
- Context propagation — request-scoped metadata in every event via
resilience_context - Opinionated presets —
http_policy(),db_policy(),queue_policy() - Production observability — JSON logging, metrics, OpenTelemetry spans, Prometheus counters/histograms
- Health check — inspect circuit breaker states, in-flight calls, rate limiter availability
- Graceful shutdown — drain in-flight calls with configurable timeout
- Optional performance backends — uvloop + orjson
- Python 3.9+ — tested on 3.9 through 3.14
- Production/Stable — 365 tests, 96% branch coverage, 10.4x faster than tenacity
Why Not Just Tenacity + PyBreaker?¶
With separate libraries, you end up stacking decorators that don't share state:
# Three libraries, three configs, no coordination
from tenacity import retry, stop_after_attempt, wait_exponential
from pybreaker import CircuitBreaker
from wrapt_timeout_decorator import timeout
breaker = CircuitBreaker(fail_max=5)
@timeout(10)
@breaker
@retry(stop=stop_after_attempt(3), wait=wait_exponential())
def call_api():
return requests.get("https://api.example.com/data").json()
# No fallback. No rate limiting. No caching. No shared metrics.
# The circuit breaker doesn't know about retries. Timeouts don't coordinate with backoff.
With pyresilience, everything is coordinated through one decorator:
import requests
from pyresilience import resilient, RetryConfig, TimeoutConfig, CircuitBreakerConfig
from pyresilience import FallbackConfig, RateLimiterConfig, CacheConfig
@resilient(
retry=RetryConfig(max_attempts=3, delay=1.0),
timeout=TimeoutConfig(seconds=10),
circuit_breaker=CircuitBreakerConfig(failure_threshold=5),
fallback=FallbackConfig(handler=lambda e: {"error": "service unavailable"}),
rate_limiter=RateLimiterConfig(max_calls=100, period=60.0),
cache=CacheConfig(max_size=256, ttl=300.0),
)
def call_api():
return requests.get("https://api.example.com/data").json()
# One decorator. All patterns. Shared state. Unified metrics.
The circuit breaker counts retried failures correctly. Rate limiting respects bulkhead limits. Cache short-circuits the entire pipeline. One event system observes everything.
Observability at a Glance¶
Every resilience event — retries, circuit state changes, rate limit hits — can be observed with listeners:
from pyresilience import resilient, RetryConfig, CircuitBreakerConfig
from pyresilience import JsonEventLogger, MetricsCollector, EventType
logger = JsonEventLogger()
metrics = MetricsCollector()
def alert_on_circuit_open(event):
if event.event_type == EventType.CIRCUIT_OPEN:
print(f"ALERT: Circuit opened for {event.function_name}")
@resilient(
retry=RetryConfig(max_attempts=3),
circuit_breaker=CircuitBreakerConfig(failure_threshold=5),
listeners=[logger, metrics, alert_on_circuit_open],
)
def payment_service(amount: float):
return process_payment(amount)
# After some calls, check metrics:
# metrics.summary() -> {"total_events": 150, "success_rate": 0.95, ...}
See Observability for the full event system, JSON logging, and metrics collection.
FastAPI Integration¶
Use pyresilience with FastAPI's dependency injection for per-route resilience:
from fastapi import Depends, FastAPI
from pyresilience import ResilienceConfig, RetryConfig, CircuitBreakerConfig
from pyresilience.contrib.fastapi import ResilientDependency
app = FastAPI()
payment_resilience = ResilientDependency(ResilienceConfig(
retry=RetryConfig(max_attempts=3),
circuit_breaker=CircuitBreakerConfig(failure_threshold=5),
))
@app.post("/charge")
async def charge(
amount: float,
resilience: ResilientDependency = Depends(payment_resilience),
):
return await resilience.call(payment_service.charge, amount)
Also supports Django and Flask.
Next Steps¶
- Installation — Get started in 30 seconds
- Quick Start — Your first resilient function
- Core Modules — Deep dive into each pattern
- Observability — Logging, metrics, and alerting
- Framework Integrations — FastAPI, Django, Flask