🔁 retrykit
A clean, simple retry decorator for Python — sync, async, backoff, jitter, and custom exceptions.
🤔 Why retrykit?
Network calls fail. APIs go down. Databases time out.
Instead of writing manual retry loops every time, just add @retry and it handles everything for you.
# Without retrykit — ugly, repetitive
for attempt in range(3):
try:
result = requests.get(url)
break
except Exception:
if attempt == 2:
raise
time.sleep(1)
# With retrykit — clean and simple
@retry(times=3, delay=1)
def fetch():
return requests.get(url)
📦 Installation
pip install retrykit
🚀 Quick Start
from retrykit import retry
@retry(times=3, delay=1)
def fetch_data():
return requests.get("https://api.example.com").json()
That's it. If fetch_data() fails, it retries up to 3 times, waiting 1 second between attempts.
⚙️ All Options
@retry(
times=3, # Total attempts (default: 3)
delay=1.0, # Seconds to wait between retries (default: 1.0)
backoff=1.0, # Multiply delay by this after each retry (default: 1.0)
jitter=False, # Add small random delay to avoid thundering herd (default: False)
on=None, # List of exceptions to retry on (default: any Exception)
on_retry=None, # Callback called before each retry
)
📖 Examples
Basic Retry
from retrykit import retry
@retry(times=3, delay=2)
def connect_to_server():
return requests.get("https://api.example.com")
Exponential Backoff
Delays grow: 1s → 2s → 4s → 8s
@retry(times=4, delay=1, backoff=2)
def fetch_with_backoff():
return requests.get("https://api.example.com")
Retry Only on Specific Exceptions
@retry(times=3, delay=1, on=[ConnectionError, TimeoutError])
def connect_db():
return db.connect()
# TypeError or ValueError won't be retried — they raise immediately
Jitter (Avoid Thundering Herd)
Adds a small random delay so multiple clients don't hammer a server at the same time.
@retry(times=3, delay=2, jitter=True)
def api_call():
return requests.post("https://api.example.com/data", json=payload)
on_retry Callback
Run custom logic before each retry (logging, alerting, etc.)
def log_retry(attempt, exception, next_delay):
print(f"Attempt {attempt} failed: {exception}. Retrying in {next_delay}s...")
@retry(times=3, delay=1, on_retry=log_retry)
def risky_operation():
return do_something_risky()
Async Support
Works with async def functions automatically — no extra config needed.
@retry(times=3, delay=1)
async def async_fetch():
async with aiohttp.ClientSession() as session:
async with session.get("https://api.example.com") as resp:
return await resp.json()
Real-World Example
import requests
from retrykit import retry
def log_retry(attempt, exc, delay):
print(f"[Warning] Attempt {attempt} failed: {exc}. Retrying in {delay}s...")
@retry(
times=5,
delay=1,
backoff=2,
jitter=True,
on=[requests.ConnectionError, requests.Timeout],
on_retry=log_retry,
)
def fetch_weather(city: str):
response = requests.get(
f"https://api.openweathermap.org/data/2.5/weather?q={city}",
timeout=5
)
response.raise_for_status()
return response.json()
data = fetch_weather("Chennai")
🆚 retrykit vs tenacity
| Feature | retrykit | tenacity |
|---|---|---|
| Simple decorator API | ✅ Clean | ⚠️ Verbose |
| Async support | ✅ Auto-detected | ✅ Manual |
| Exponential backoff | ✅ backoff=2 |
✅ wait_exponential() |
| Jitter | ✅ jitter=True |
✅ wait_random() |
| Zero dependencies | ✅ Pure stdlib | ✅ |
| Learning curve | ✅ Beginner-friendly | ⚠️ Complex |
🧪 Running Tests
pip install pytest
pytest tests/ -v
📄 License
MIT — free to use in personal and commercial projects.
🤝 Contributing
Pull requests are welcome! Please open an issue first to discuss changes.
- Fork the repo
- Create a branch:
git checkout -b feature/my-feature - Make your changes + add tests
- Open a Pull Request
Metadata
Release files for retrykit-simple 0.1.1
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_simple-0.1.1.tar.gz | 6.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| retrykit_simple-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 12.7 kB
Release files / retrykit_simple-0.1.1.tar.gz
| Download URL | retrykit_simple-0.1.1.tar.gz |
|---|---|
| Size | 6.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fae23b7d4aed6cb39e2578d53fdde9f4c079b79f9bb9a5186fdf6eaa8ab5585f
|
|
BLAKE2b-256 checksum How to use checksums |
aab803a770a93fdb83d35b95640f2727fc6dcc9b96f44ca4f5dcc1b674a40f23
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.5
|
Release files / retrykit_simple-0.1.1-py3-none-any.whl
| Download URL | retrykit_simple-0.1.1-py3-none-any.whl |
|---|---|
| Size | 5.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
35989bfb0c9637d44eb0b440ee9aba1ad8282ab21a3a63cee96acbcded5023de
|
|
BLAKE2b-256 checksum How to use checksums |
0852b69ee16c89fac19eea56fd073509991c10ea96ece841bce50cd4a9271812
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.5
|