ediverse Explore the platform

Spotlight PEPPOL BIS Billing 3.0 The EU e-invoicing mandate is here — France Sept 2026, Belgium Jan 2026, Germany 2025.

Retry With Jitter (anti retry storm)

The retry pattern that adds controlled randomness to exponential backoff to break client synchronisation and avoid shock amplification during partner outage.

Problem

An AS2 partner goes down for 5 minutes. During these 5 minutes, 50 EDI clients try to send, fail, and trigger their retry. If all use pure exponential backoff (1s, 2s, 4s, 8s, 16s, 32s, 64s), at the moment the partner recovers, the 50 retry almost simultaneously — the partner is immediately re-saturated and falls again. This is the retry storm or thundering herd: the cure becomes worse than the disease.

Forces

  • Retries are necessary: without retry, any transient failure = lost message.
  • Exponential backoff alone is insufficient: it synchronises clients on discrete instants.
  • Randomness must be quality pseudo-random: Math.random suffices, no need for cryptographic.
  • Retry aggregate must be bounded: after N attempts, abandon and route to Dead Letter Channel.
  • Idempotency must be guaranteed: a retry sends the same message, so the server must dedupe.

Solution

Add a random jitter factor to the retry interval. Three main variants documented in the reference AWS article (Marc Brooker, 2015):

  • Exponential Backoff + Full Jitter: sleep = random(0, min(cap, base * 2^attempt)). The reference case: distribution uniform over the entire interval.
  • Equal Jitter: sleep = min(cap, base * 2^attempt) / 2 + random(0, min(cap, base * 2^attempt) / 2). Compromise that guarantees a minimum but stays partially random.
  • Decorrelated Jitter: sleep = min(cap, random(base, sleep * 3)). Iterative, good statistical behaviour in simulation.

Modern libraries (AWS SDK, Resilience4j, Polly .NET, Tenacity Python) integrate Full Jitter by default.

Three retry strategies:

1. Pure exponential (BAD — retry storm)
   attempt 1: T+1s
   attempt 2: T+2s
   attempt 3: T+4s
   attempt 4: T+8s
   → all clients retry together: shock amplified

2. Exponential + Full Jitter (Marc Brooker, AWS 2015)
   attempt N: random(0, min(MAX, BASE * 2^N))
   attempt 1: random(0, 2s)   → e.g. 1.3s
   attempt 2: random(0, 4s)   → e.g. 2.8s
   attempt 3: random(0, 8s)   → e.g. 5.1s
   attempt 4: random(0, 16s)  → e.g. 14.7s
   → distribution is uniform over the interval, breaks synchronisation

3. Decorrelated Jitter (AWS queue variant)
   sleep = min(cap, random(BASE, sleep * 3))
   → progresses ergodically, balances exploration / convergence

EDI implementation

Concrete case: 50 simultaneous AS2 sends to the same partner, timeout 30s. The partner returns 503 + Retry-After 60. Without jitter: at T+60s, 50 clients retry, hit the same second, partner re-saturated. With Full Jitter: each client retries after random(0, 120s), uniformly distributed over 2 minutes. The partner takes 50 spread-out requests, recovers normally, success rate climbs back. Java code with Resilience4j: RetryConfig config = RetryConfig.custom().maxAttempts(5).intervalFunction(IntervalFunction.ofExponentialRandomBackoff(1000, 2.0, 30000)).build();. AS2-specific: also respect Retry-After when provided, and combine with Circuit Breaker to open the circuit after failure threshold. For time-constrained fiscal flows (ZATCA clearance, India IRP), document maximum retry window in the SLA.

Anti-patterns

  • Exponential retry without jitter: retry storm stays possible, especially in multi-instance architectures.
  • Retry without cap: 100 attempts, 1h accumulated, message that will never go out → blocks the queue indefinitely.
  • Retry without idempotency: the partner receives the same order 5 times, processes 5 times → 5 deliveries, accounting disaster.
  • Retry of everything: retrying a 401 Unauthorized error is pointless, retry should depend on error type (transient vs permanent).
  • Jitter too small: random(0, 100ms) on a 60s exponential sleep breaks nothing — jitter must be of the same order of magnitude as the sleep.
  • No associated circuit breaker: if the outage lasts 10h, continuing to retry uselessly loads the network and amplifies costs.

Sources