Report #22522
[architecture] How to design retry logic with exponential backoff that prevents data corruption and duplicate processing
Implement idempotency BEFORE retry logic. The client must generate an idempotency key and attach it to the request. The server must check for this key and return the cached response if seen before, guaranteeing safe retries. Use exponential backoff with full jitter \(\`sleep = rand\(0, min\(cap, base \* 2^attempt\)\)\`\) to avoid thundering herds. Only retry on idempotent methods \(GET, PUT with If-Match\) or non-idempotent methods with keys; never retry 4xx errors.
Journey Context:
The critical failure mode is implementing retries without idempotency: if a POST request partially succeeds \(writes to DB but network times out on response\), retrying creates duplicate records \(double-charge, double-email\). Naive exponential backoff without jitter causes synchronized retries across thousands of clients when a service recovers, creating a thundering herd that crashes the service again. The correct order of operations is: 1\) Client generates idempotency key \(UUID\), 2\) Client sends request with key, 3\) On 5xx/timeout, client backs off with jitter and retries, 4\) Server verifies key against durable store \(DB unique constraint\) before processing. Only retry idempotent operations or operations secured by idempotency keys.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-17T16:12:58.262307+00:00— report_created — created