nopanic¶
The unified resilience toolkit for Python. Retries, circuit breakers, timeouts, rate limits, bulkheads, hedged requests, retry budgets and deadlines: one decorator-based API, identical for sync and async code (streams included), with zero runtime dependencies.
from nopanic import backoff, circuit_breaker, retry, timeout
llm_breaker = circuit_breaker(failure_threshold=0.5, reset_timeout=15.0, name="llm")
@retry(attempts=4, on=ConnectionError, backoff=backoff.full_jitter(base=0.2, cap=10.0))
@llm_breaker
@timeout(30.0)
async def call_llm(prompt: str) -> str:
...
pip install nopanic
Python 3.10+, fully typed. Runs on asyncio, Trio and AnyIO.
Why¶
Java has resilience4j, .NET has Polly. Python has a drawer of single-purpose parts that were never designed to work together. These patterns only pay off when they compose: a timeout per attempt, retries that respect an open circuit and a shared retry budget, a deadline for the whole operation, a fallback that catches whatever is left. nopanic is that set of parts, built as one system.
| You need | nopanic |
|---|---|
| Retry with backoff, Retry-After, result checks | retry |
| Stop calling what is down (and what is too slow) | circuit_breaker |
| Bound each call, each stream item | timeout |
| Respect quotas, or discover them (AIMD) | rate_limit, adaptive_rate_limit |
| Cap concurrency | bulkhead |
| Degrade gracefully | fallback |
| Fix tail latency | hedge |
| Survive outages with stale data | cache |
| One time budget per operation | deadline |
| Stop retry storms | RetryBudget |
| One breaker per host or tenant | keyed |
| Shared state across a fleet | nopanic-redis |
| Metrics and traces | events, nopanic-otel |
Principles¶
- Zero dependencies. A resilience library must not be a reliability risk itself.
- Sync and async are equals. One API; the wrapper flavour is chosen at decoration time.
- No wrapper exceptions. Your
except ConnectionError:keeps working; policies add only their own precise signals (CircuitOpen,BulkheadFull,RateLimited) and the builtinTimeoutError. - Composition over configuration. Small orthogonal policies and
compose, not one object with forty options. - Fail loudly at decoration time. A policy that cannot guard what you decorated says so immediately.
- Testable time. Injectable clocks and
testing.instant(): your test suite never sleeps.