Have you ever wondered when one service calls to another service and you get no response back? its hard to tell of the other side is slow , dead or message got lost. These are 4 techniques how systems cope.
I give you what these terms are with analogy and the CS term as well for better understand.
Timeouts
Analogy: You call a restaurant and it just rings. Eventually you hang up instead of waiting forever.
In CS: A timeout is the maximum time a client waits for a response before treating the request as failed. Without one, stuck requests hold threads and connections until the caller runs out of resources, and one slow service drags down everything that depends on it. Note that a timeout doesn’t mean the work didn’t happen; the server may have finished and the reply got lost.
Retries
Analogy: You hung up, so you call again. Often someone picks up the second time.
In CS: A retry re-sends a failed request, which turns transient failures (dropped packets, restarting servers) into successes. Two cautions: only retry idempotent operations (or use an idempotency key), or you might charge a card twice; and cap attempts, because retries add load to a service that may already be struggling.
Exponential backoff
Analogy: You don’t hit redial every second. You wait one minute, then five, then fifteen.
In CS: Backoff is the wait between retries, usually doubling each time up to a cap: delay = min(cap, base * 2^attempt), e.g. 100 ms, 200 ms, 400 ms, 800 ms. Short blips get retried quickly, while real outages get breathing room to recover.
Jitter
Analogy: When a concert ends, 20,000 people rushing one exit at once jams it. Staggered, they all get through.
In CS: If thousands of clients fail together and use the same backoff, they retry in synchronized waves that knock the recovering server down again: the thundering herd. Jitter adds randomness to each delay so retries spread out. Full jitter, sleep = random(0, backoff), is a solid default.
Putting it together
Wait a limited time, retry a few times, wait longer between tries, and randomize the wait.
In code, the whole pattern fits in a few lines. Here’s a TypeScript sketch:
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
async function fetchWithRetries(
url: string,
{ maxAttempts = 4, baseMs = 100, capMs = 10_000, timeoutMs = 2_000 } = {}
): Promise<Response> {
for (let attempt = 0; ; attempt++) {
try {
const res = await fetch(url, { signal: AbortSignal.timeout(timeoutMs) }); // 1. timeout
if (res.status !== 429 && res.status < 500) return res; // success or non-retryable error
throw new Error(`Retryable status ${res.status}`);
} catch (err) {
if (attempt >= maxAttempts - 1) throw err; // give up eventually
const backoff = Math.min(capMs, baseMs * 2 ** attempt); // 3. exponential backoff
await sleep(Math.random() * backoff); // 4. full jitter
// 2. loop around and retry
}
}
}