Smarter retry policies for real systems
Retries seem simple until you need them to behave correctly in production.
Most Python retry libraries treat all failures the same. They give you one decorator, one backoff model, and one global set of rules.
But real systems don’t fail uniformly:
Reflexio exists because real systems need intelligent, structured retry behavior, not blanket rules.
After years building distributed compute engines, internal APIs, and latency-sensitive services, I kept running into the same retry problems:
Retry logic is deceptively subtle. It needs structure, classification, observability, and predictability. So I wrote a library that reflects how real services behave.
Reflexio focuses on four core principles:
Errors are first mapped into coarse “error classes,” which then determine retry behavior. This keeps policy logic clean and predictable.
TimeoutError -> TRANSIENT
ConnectionError -> TRANSIENT
429 / rate limit -> RATE_LIMIT
400 / validation -> PERMANENT
Different error classes should use different backoff strategies:
Retries without structured events are a debugging nightmare.
Reflexio provides a single callback that surfaces:
This makes logging and metrics integration trivial.
The API is intentionally small:
RetryPolicyAsyncRetryPolicy@retry decoratordecorrelated_jitter, equal_jitter, etc.)No magic, no stack-trace pollution, no surprise behaviors.
A simple table to illustrate where Reflexio fits in the retry ecosystem:
| Feature | reflexio | Tenacity | backoff |
|---|---|---|---|
| Exception classification | ✅ | ⚠️ manual | ❌ |
| Per-class strategies | ✅ | ⚠️ partial | ❌ |
| Structured observability hooks | ✅ | ❌ | ❌ |
| Decorators | ✅ | ✅ | ✅ |
| Async support | ✅ | ⚠️ | ⚠️ |
| Decorrelated jitter | ✅ | ❌ | ⚠️ |
| Small, explicit API | ✅ | ❌ (large) | ⚠️ |
| Deterministic envelopes | ✅ | ❌ | ⚠️ |
Reflexio isn’t meant to replace Tenacity or backoff; it’s built for situations where controlling retry behavior per class of failure actually matters.
from reflexio import retry, default_classifier
from reflexio.strategies import decorrelated_jitter
@retry(
classifier=default_classifier,
strategy=decorrelated_jitter(max_s=10.0),
)
def fetch_data():
...
Async support works similarly:
from reflexio import AsyncRetryPolicy, default_classifier
async_policy = AsyncRetryPolicy(
classifier=default_classifier,
strategy=decorrelated_jitter(max_s=5.0),
)
Modern systems rely heavily on:
All of them fail in different ways, for different reasons, with different recommended backoff patterns.
Retries are not an afterthought; they’re part of the reliability surface of your application.
Reflexio makes this reliability explicit, structured, and observable… without bloated abstractions or hidden behavior.
GitHub
https://github.com/aponysus/reflexio
PyPI
https://pypi.org/project/reflexio/
pip install reflexio
The project is intentionally small and easy to grok. Future planned topics:
If any of that interests you, PRs are welcome.