In this lesson, you will learn how to implement exponential backoff to prevent "thundering herd" problems when your Node.js services interact with struggling downstream dependencies.
The Problem: The Thundering Herd
When an external API or database becomes unreachable, a common mistake is to retry the request immediately. If you retry every 100ms, and you have multiple instances of your service doing the same, you inadvertently launch a Denial-of-Service attack on the recovering system. It cannot process the backlog because it is overwhelmed by your constant retry traffic.
The Strategy: Exponential Backoff
Exponential backoff solves this by increasing the wait time between retries exponentially. If a call fails, you wait, say, 1 second. If it fails again, you wait 2 seconds, then 4, then 8, and so on. This gives the downstream system "breathing room" to recover.
To prevent synchronization—where all your service instances retry at the exact same moment—we also add "jitter," a small amount of random noise to the wait time.
Implementing the Loop
Here is a pattern for an asynchronous retry loop:
async function fetchWithRetry(fn, maxRetries = 5) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
if (attempt === maxRetries) throw error;
// Exponential delay: 1s, 2s, 4s, 8s...
const delay = Math.pow(2, attempt) * 1000;
// Adding jitter (±20% of the delay)
const jitter = delay * 0.2 * Math.random();
console.warn(`Attempt ${attempt} failed. Retrying in ${delay + jitter}ms...`);
await new Promise(resolve => setTimeout(resolve, delay + jitter));
}
}
}
By calculating Math.pow(2, attempt), we ensure the wait duration grows rapidly. The jitter ensures that even if ten instances fail at once, they won't all hit the dependency at the exact same millisecond when they come back up. This approach balances your system's need for data with the target service's need for stability.
Key Takeaway: Exponential backoff combined with jitter protects recovering systems by spreading out retry traffic over time, preventing service collapse during outages.