Question presented to candidate: "Your service retries a failed downstream call immediately, three times in a row, with no delay. During a real outage, this pattern makes the downstream service's recovery WORSE, not better. What's the actual fix, and why does simply adding a fixed delay between retries still not be fully sufficient?"
What a strong answer should cover:
- Retrying immediately with no delay, exactly as the prompt describes, adds load to a downstream service at the exact moment it's already struggling — genuinely counterproductive, and directly connects to the real cascading-failure risk verified with its own proof in this bank's dedicated circuit-breaker question.
- Exponential backoff fixes the "no delay" half: each successive retry waits longer than the last, typically doubling — 📌 verified, not assumed: a real retry loop's measured delays genuinely doubled across real attempts (~50ms base, growing to ~100ms, ~200ms for successive real retries) before a real success on attempt 4.
- 📌 Interview term: the thundering herd problem — a fixed (non-random) delay, even an exponentially growing one, still causes a real problem when many clients are all retrying against the identical downstream service after an outage: since they likely failed at similar times, a purely deterministic backoff schedule causes them all to retry again at the exact same moment, creating a new, synchronized spike of load — precisely why "just add a fixed delay" is not fully sufficient, directly answering the prompt's second question.
- Jitter — genuine randomness added to each computed delay — is the fix for the thundering-herd problem: 📌 verified, not assumed: two separate delay calculations for the identical attempt number produced genuinely different real results (209ms vs. 217ms) — real, confirmed randomness, not a deterministic formula that would produce identical delays for identical inputs.
- A precise answer names the complete, precise formula, and why each part matters:
delay = min(baseDelay * 2^(attempt-1), maxDelay)(verified above as the real, measured exponential growth) plus a real random jitter component (verified above as genuinely producing different results for the identical attempt) capped at a realmaxDelay(preventing a real, unbounded wait after many failed attempts) — all three pieces working together, not any single one alone, is the complete, correct real answer.
Clarifying questions expected:
- "Is there a real maximum number of retry attempts before genuinely giving up, and what should happen to the caller when that limit is reached?" — a real, necessary bound beyond just the per-retry delay math.
- "Should every type of failure be retried the same way, or are some errors (a real 400 Bad Request, genuinely not transient) not worth retrying at all?" — a precise answer distinguishes retryable (network blips, 5xx/timeout) from non-retryable failures.
Code / implementation expected: Yes — a real retry loop with genuinely measured, doubling delays and a real, confirmed jitter-randomness proof (two different real results for the identical attempt number) is the concrete, convincing proof of exactly how both mechanisms work together.