A clean, simple retry decorator for Python — sync, async, backoff, jitter.
Project description
🔁 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
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_simple-0.1.1.tar.gz.
File metadata
- Download URL: retrykit_simple-0.1.1.tar.gz
- Upload date:
- Size: 6.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fae23b7d4aed6cb39e2578d53fdde9f4c079b79f9bb9a5186fdf6eaa8ab5585f
|
|
| MD5 |
74e6f1f309c7105f90b9749eb7e7e6c4
|
|
| BLAKE2b-256 |
aab803a770a93fdb83d35b95640f2727fc6dcc9b96f44ca4f5dcc1b674a40f23
|
File details
Details for the file retrykit_simple-0.1.1-py3-none-any.whl.
File metadata
- Download URL: retrykit_simple-0.1.1-py3-none-any.whl
- Upload date:
- Size: 5.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
35989bfb0c9637d44eb0b440ee9aba1ad8282ab21a3a63cee96acbcded5023de
|
|
| MD5 |
c547497428f1972e06c096f1e92c5bdd
|
|
| BLAKE2b-256 |
0852b69ee16c89fac19eea56fd073509991c10ea96ece841bce50cd4a9271812
|