Skip to main content
ZombieMutex

30 results · ↑ ↓ navigate · Enter open · Esc close

All writing
November 7, 20263 min read

Retry storms: when resilience multiplies a failure

Retry logic looks harmless in isolation. When a gateway, application service and SDK each apply their own retry policy, a single failed operation can multiply into a dependency outage. That interaction is the starting point for my retry-storm analysis.

By

Share

Send this article to someone or copy its link.

Suggest a correction

Reader tools

3 min remaining · 0% of article

Select a passage and choose Highlight selection to save it. Local browser storage only. Shift+F toggles focus.

Case file / Retro schematic

Reported sequence and proposed controls

Explore a simplified sequence from the cited research, then switch to defensive checkpoints. These are explanatory diagrams, not live samples, executed code, or original incident telemetry.

Reported sequence

  1. Dependency slows
  2. Clients time out
  3. Retries amplify demand
  4. Budget and jitter limit load

Proposed defensive checks

  1. Set retry ownership
  2. Enforce attempt budget
  3. Add randomized backoff
  4. Preserve idempotency keys

Simplified sequence based on cited research; proposed defenses are not evidence that the incident was prevented.

Retry logic looks harmless in isolation. When a gateway, application service and SDK each apply their own retry policy, a single failed operation can multiply into a dependency outage. That interaction is the starting point for my retry-storm analysis.

The problem is not that retrying is always wrong; it is that each layer can add traffic at the worst possible moment.

The amplification hidden in a call chain

Suppose an API gateway, service A and service B each allow three attempts. A single end-user operation can trigger up to 27 downstream calls if every layer independently retries a failing dependency. That's a worst-case arithmetic illustration, not measured traffic from this site.

Timeouts complicate mutating requests further. A client can give up before the server commits; sending a fresh operation creates the possibility of a duplicate side effect.

The controls that bound the failure

  • One retry owner per operation path. Document which layer is responsible; don't hide nested retries inside SDK defaults.
  • Bounded attempts and deadline. Stop retrying when the operation's useful response window has expired.
  • Exponential backoff with jitter. Spread retries rather than synchronizing on fixed intervals.
  • Idempotency for mutations. Preserve the operation key across retries; don't assume a timeout means the operation failed.
  • Overload feedback. Circuit breaking and rate limiting are more useful than blindly increasing request concurrency when a service is unhealthy.

A retry budget is a control-plane decision about reliability and cost. An idempotency key is an application contract about effects. Neither replaces the other.

One reproducible experiment

A useful reproduction uses a synthetic dependency with a fixed failure window, then compares fixed-delay and jittered retries under a known seed. The result is incomplete if it only records eventual success; peak in-flight requests, work amplification and tail latency determine whether a retry policy protects or overloads a service.

The existing idempotency reference test checks a different boundary: duplicate mutation suppression in one process. It should not be used as evidence for distributed retry-storm behavior.

The next step would be a controlled load test: fix the dependency failure window, choose one retry owner, and measure peak in-flight work, tail latency, and total dependency requests across multiple retry policies. No distributed benchmark is claimed here.

A review of the call chain should document:

  1. Where the gateway or SDK may retry the same operation.
  2. Which service owns the retry budget and preserves idempotency keys.
  3. How downstream overload and timeout ambiguity are surfaced to the caller.

Source

AWS Builders' Library: timeouts, retries and backoff with jitter

Scope: Architecture analysis and a proposed load test; no distributed benchmark was run for this note.

Related technical notes with overlapping topics.

Discuss a passage

Select a paragraph above, copy it with its article link, then paste into the discussion. Don't include private data.

Jump to discussion ↓

Public conversation / GitHub Discussions

Discuss this article

Read and reply using GitHub Discussions. A GitHub account is needed to post. Comments are public and subject to GitHub moderation.

For privacy, the external giscus widget does not load until you choose to open it. Opening it connects your browser to giscus and GitHub. Do not post credentials or private project data.