retrykit (Python)
Retry logic and circuit breakers with an identical API in Python and TypeScript.
- ✅
@retrydecorator andRetryingcontext manager - ✅ Built-in circuit breaker (
CLOSED → OPEN → HALF_OPEN → CLOSED) - ✅ Sync and async, transparently
- ✅ Automatic OpenTelemetry spans when
opentelemetry-apiis installed - ✅ Zero required dependencies, fully typed (
py.typed)
Install
pip install retrykit
# with OpenTelemetry spans:
pip install "retrykit[otel]"
Quick start
from retrykit import retry
@retry(attempts=3)
async def call_api() -> str:
...
Full options
@retry(
attempts=5,
backoff="exponential", # "fixed" | "linear" | "exponential"
delay=1.0, # base delay in seconds
max_delay=60.0,
jitter=True, # full jitter to avoid thundering herd
on=["HTTPError", "TimeoutError"], # retry only on these (class or name)
on_retry=lambda attempt, error: print(f"Retry {attempt}: {error}"),
)
async def call_openai(prompt: str) -> str:
...
Circuit breaker
from retrykit import circuit_breaker, CircuitBreaker, CircuitOpenError
@circuit_breaker(threshold=5, timeout=30, on_open=lambda: print("opened!"))
async def call_stripe(): ...
# Or standalone:
breaker = CircuitBreaker(threshold=5, timeout=30)
result = breaker.call(do_work) # sync
result = await breaker.call_async(work) # async
print(breaker.state) # CircuitState.CLOSED / OPEN / HALF_OPEN
Composable
@retry(attempts=3, backoff="exponential")
@circuit_breaker(threshold=5, timeout=30)
async def resilient_call(): ...
Context-manager style
from retrykit import Retrying
async with Retrying(attempts=3, backoff="exponential") as r:
async for attempt in r:
with attempt:
result = await call_api()
The sync form is identical without the async keywords:
with Retrying(attempts=3) as r:
for attempt in r:
with attempt:
result = call_api()
API reference
retry(attempts=3, *, backoff="exponential", delay=1.0, max_delay=60.0, jitter=False, on=None, on_retry=None)
Decorator. Retries up to attempts times. Raises RetryError (with
.last_exception) when exhausted. on accepts exception classes or their
string names; None retries on any Exception.
Retrying(...)
Same options as retry; usable as a sync or async context manager / iterator.
circuit_breaker(threshold=5, timeout=30, *, on_open=None, on_close=None)
Decorator. The underlying CircuitBreaker is exposed on the wrapped function as
.breaker. Raises CircuitOpenError while open.
CircuitBreaker(threshold=5, timeout=30.0, *, on_open=None, on_close=None)
.call(fn, *a, **kw), await .call_async(fn, *a, **kw), .state,
.failure_count, .reset().
OpenTelemetry
If opentelemetry-api is importable, every attempt is wrapped in a span named
retry.attempt:<func> with attributes retry.attempt, retry.max_attempts,
and retry.failed. If it is not installed, span creation is silently skipped —
no configuration required.
Development
pip install -e ".[dev]"
pytest --cov=retrykit
mypy
ruff check retrykit
License
MIT
Release files for retrykit-lib 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| retrykit_lib-0.1.0.tar.gz | 11.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| retrykit_lib-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 22.9 kB
Release files / retrykit_lib-0.1.0.tar.gz
| Download URL | retrykit_lib-0.1.0.tar.gz |
|---|---|
| Size | 11.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4cfc80e9a0096e188f7f4d966903f29bd72568a46e2941a5ab25315831e76dd6
|
|
BLAKE2b-256 checksum How to use checksums |
41db08389ccafc057cc587cf797ded5c9fb748b3dbe599a897af9efd55455a34
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.11
|
Release files / retrykit_lib-0.1.0-py3-none-any.whl
| Download URL | retrykit_lib-0.1.0-py3-none-any.whl |
|---|---|
| Size | 11.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f8ac9074609a79db62d7fa1bc6820c2cb7849b853c2929df297df57eec2f087b
|
|
BLAKE2b-256 checksum How to use checksums |
33cd57347d06397fef34afab8e9e3ceab2c08ebc503274408e2aec885d756154
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.11
|