Retry logic and circuit breakers with an identical API in Python and TypeScript.
Project description
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
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 retrykit_lib-0.1.0.tar.gz.
File metadata
- Download URL: retrykit_lib-0.1.0.tar.gz
- Upload date:
- Size: 11.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4cfc80e9a0096e188f7f4d966903f29bd72568a46e2941a5ab25315831e76dd6
|
|
| MD5 |
cf0088d802bbd144c78daed9e071c002
|
|
| BLAKE2b-256 |
41db08389ccafc057cc587cf797ded5c9fb748b3dbe599a897af9efd55455a34
|
File details
Details for the file retrykit_lib-0.1.0-py3-none-any.whl.
File metadata
- Download URL: retrykit_lib-0.1.0-py3-none-any.whl
- Upload date:
- Size: 11.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f8ac9074609a79db62d7fa1bc6820c2cb7849b853c2929df297df57eec2f087b
|
|
| MD5 |
56ec3478ca9c74340a20c6e92c029f35
|
|
| BLAKE2b-256 |
33cd57347d06397fef34afab8e9e3ceab2c08ebc503274408e2aec885d756154
|