🔁 I Was Tired of Writing Retry Logic… So I Built retry-pro
Every backend developer has written this at least once:
for (let i = 0; i < 3; i++) {
try {
return await fetchData();
} catch (e) {
await new Promise(r => setTimeout(r, 1000));
}
}
Looks harmless, right?
Until production hits.
💥 The Night Everything Broke
2:17 AM.
Your API starts failing randomly.
- Third-party service → timing out
- Database → occasional connection drops
- Users → getting errors
You panic… but then remember:
“We added retry logic!”
Except… you didn’t really.
🚨 The Hidden Problem With “Simple” Retries
That tiny loop you wrote?
It’s missing a lot:
- ❌ No exponential backoff
- ❌ No jitter → causes traffic spikes
- ❌ Retries everything (even bad requests 🤦)
- ❌ No timeout per attempt
- ❌ No logs, no hooks, no visibility
What you thought was resilience… is actually risk.
🧠 What Production-Grade Retry Actually Looks Like
Here’s what you really need:
Attempt 1 → wait 200ms
Attempt 2 → wait 400ms
Attempt 3 → wait 800ms (+ jitter)
Stop retrying if error is NOT retryable
Timeout each attempt individually
Log everything
That’s not a loop anymore.
That’s a system.
✨ Meet retry-pro
Instead of rewriting this logic every time, I built:
👉 retry-pro — a tiny but powerful async retry utility
⚡ What Makes It Different?
- 🔁 Exponential backoff (built-in)
- 🎲 Optional jitter (prevents retry storms)
- ⏱️ Timeout per attempt
- 🧠 Smart retry conditions
- 🪝 Hooks:
onRetry,onSuccess,onFailure - 🧩 TypeScript support
🚀 10-Second Setup
npm install retry-pro
import { retryAsync } from "retry-pro";
const data = await retryAsync(fetchData, {
retries: 3
});
That’s it. You already have safer retries.
🔬 Real Example (The Right Way)
const user = await retryAsync(async () => {
const res = await fetch("/api/user");
if (!res.ok) {
const err = new Error("Request failed");
err.retryable = res.status >= 500;
throw err;
}
return res.json();
}, {
retries: 5,
initialDelay: 200,
maxDelay: 5000,
jitter: true,
retryIf: (err) => err.retryable,
onRetry: (attempt, err, delay) => {
console.log(`Retry ${attempt} in ${delay}ms`);
}
});
📊 Visualizing the Difference
❌ Naive Retry
[Request] → fail → wait 1s → fail → wait 1s → fail ❌
✅ Smart Retry (retry-pro)
[Request]
↓
fail → wait 200ms
↓
fail → wait 400ms (+ jitter)
↓
fail → wait 800ms
↓
success ✅
🌍 Where This Actually Saves You
- 🔌 Third-party APIs (Stripe, Firebase, etc.)
- 🌐 Fetch / Axios calls
- 🗄️ Database reconnect logic
- ⚡ Background jobs & workers
- 🔁 Microservices communication
⚖️ “Why Not Just Use p-retry?”
Good question.
Libraries like p-retry are solid.
But retry-pro focuses on:
- Cleaner DX (less boilerplate)
- Built-in lifecycle hooks
- Timeout per attempt (huge in production)
- More control, less setup
💡 Hard-Learned Lesson
Retries are not about “trying again.”
They’re about:
- timing
- control
- safety
- observability
Bad retries can DDOS your own system.
Good retries make your system feel bulletproof.
🔗 Try It Yourself
👉 https://www.npmjs.com/package/retry-pro
👇 Final Thought
If your code talks to anything over the network…
You already have failures.
The only question is:
Are you handling them properly?
If this helped, drop a ❤️ or share how you handle retries in your apps 👇
Top comments (0)