Skip to content

Retries with exponential backoff and jitter

A retry is more load on a service that is already failing. Spread retries in time, keep them to one layer, and cap their share.

Predict first

Before you read: predict

During an exam, a proctor opens a candidate's alert history. The console calls the console BFF, the BFF calls the alerts API, and the alerts API queries the exam database. The database is overloaded and answers every query with an error. On a 5xx the console makes up to 2 attempts, the BFF up to 3 and the alerts API up to 4.

How many queries reach the database for that one click?

Pick one

The 30-second version

Retry only transient failures of work that is safe to repeat: idempotent, or carrying a key. Wait longer after each failure, up to a cap, and randomise each wait, or clients that failed together retry together. Retries at several layers multiply: the bottom sees the product of every layer's attempts. So retry at one layer, within a budget.

A retry is more load on a service that is already failing. Spread retries in time, keep them to one layer, and cap their share.

How it works

Step 1 of 10

Retry only transient failures: a timeout, a dropped connection, a 503. A failure the request itself causes (a 400, a bug its data hits) repeats.
In the kitchen
  • the oven is only full, so another walk can work; an oven cold for repairs all month is not worth one → transient vs permanent failures (step 1)

Analogy: A neighbourhood's shared bread oven on baking morning

Every household bakes in the one oven, and a cook who finds it full carries her dough home and tries again later.

At the oven In the system
the oven is only full, so another walk can work; an oven cold for repairs all month is not worth one transient vs permanent failures (step 1)
asking again for a slot does no harm; paying the baking fee twice does safe to repeat (step 2)
each time she is turned away, she waits twice as long before the next walk exponential backoff (step 3)
everyone turned away at seven comes back together at ten past, then half past waves (step 4)
the baker's rule: draw a random minute inside your wait jitter (step 6)
she sends her son, who sends a neighbour's child, each told "try three times" layers multiply (step 7)
a notice on the bakehouse door: repeat trips, at most one in ten a retry budget (step 10)

In real terms: a retry is extra load. Aim it at transient failures of repeatable work, spread it in time, allow it at one place in the stack, and cap its share.

Breaks down when: cooks see the smoke from the chimney before they set out and can wait on their own. A client sees nothing until its attempt fails. And the baker can call "come back at twenty to"; a server's Retry-After is sd-overload-protection's lane.

Contrasting case: a cook who never comes back after one refusal. She adds no load, but every busy moment costs her a loaf: without retries each transient failure reaches the user.

Examples, run for real

4.1 ExamHall: the live feed restarts (EXH-1720, MR !1920)

At 09:00 on ECON-201 day the live-feed server restarted. Its 60 proctor consoles lost the stream together. On the virtual clock the server is down for 5 s, then accepts 15 reconnects a second while it warms up and answers 503 to the rest. The backoff starts at 1 s, doubling, capped at 30 s:

4.1 60 consoles · feed down 0-5 s, then 15 reconnects accepted a second · backoff 1 s doubling, cap 30 s · seed 1720
4.1 strategy       attempts in each second 0-15                        | after 5 s: busiest second | all 60 back at | attempts
4.1 none          60 60  0 60  0  0  0 60  0  0  0  0  0  0  0 45 | 60 |  61.0 s | 330
4.1 full         130 38 29 18 18 16  8  7  8  7  6  6  0  0  0  1 | 16 |  20.2 s | 294
4.1 equal        120  9 51  0 17 30 13  0  3  0 12  6  7  4  0  0 | 30 |  13.6 s | 272
4.1 decorrelated  60 24 37 15  6 18 10 12  9  8  3  1  0  0  2  0 | 18 |  14.8 s | 205

Without jitter all 60 return in the same second, again and again; each wave gets 15 in and sends 45 back to wait (steps 3–4). Every jittered strategy spreads them, so the warming server is never handed 60 at once, and all 60 are back in a third of the time or less (step 6). Full jitter also tries more often in the first second, while the server is still down. MR !1920 switched the console to full jitter.

4.2 Proof domain, catalog: 27 queries for one page view

A category page's BFF calls the search service, search calls the inventory service, and inventory queries the stock database, which fails every query. Three real local servers above a database stub:

4.2 every layer 3 attempts (page BFF 3 -> search 3 -> inventory 3): stock-database queries per page view 27 · search receives 3 · inventory receives 9
4.2 only inventory retries (page BFF 1 -> search 1 -> inventory 3):  stock-database queries per page view 3 · search receives 1 · inventory receives 1

Three attempts at each of three layers is 3 × 3 × 3 at the bottom (step 7). Letting only the layer next to the database retry leaves 3 (step 8). This chain waits between attempts not at all: waits would change when those queries arrive, not how many (step 9).

Try it

Answer first, then check. Nothing is saved.

Question 1 of 5

A catalog's search service calls the inventory service for the stock badge on every search, 100 searches a second. It makes up to 3 attempts per search, waiting 100 ms and then 200 ms, with no jitter. On a normal day about one inventory call in 50 fails with a brief 503, and the retry fixes it. During an inventory outage the calls pile on and inventory cannot recover.

Which one change still retries those brief 503s, and puts the least load on inventory while it is fully down?

Pick one

Question 2 of 5

A shop's web client library now retries failed calls automatically, up to 3 attempts. Four calls failed this morning.

For which one would that automatic retry both help and do no harm?

Pick one

Question 3 of 5

The 60 proctor consoles reconnect to the live feed with exponential backoff: 1 s, doubling, capped at 8 s, with no jitter. During a drill the feed server goes down at 09:00:00 and stays down for two full minutes. It drops 30 consoles at once; the other 30 lose the stream at 09:00:03, when it finishes shutting down.

How do the reconnect attempts reach it between 09:01:00 and 09:02:00?

Pick one

Question 4 of 5

During a price-database brownout, each failed product-page view sent 27 queries to the price database. The page's BFF calls the pricing service, which calls the price-rules service, which queries the database; each makes 3 attempts on a 5xx.

Which one change still retries a brief database 503, and adds the fewest calls to the services and the database while the database keeps failing?

Pick one

Question 5 of 5

80 storefront pods, all on release r-812, hold a connection to the price stream. When the stream restarts it is down for 5 s, then accepts 20 reconnects a second and answers 503 to the rest. The pods all reconnect with:

Yet after every restart all 80 attempts land in the same second, wave after wave.

Which one change keeps every second after the restart to 40 reconnect attempts or fewer, with all 80 pods back within 30 s?

Code for this question
const rand = seededRandom(config.release);   // a seeded generator, so a run can be replayedfor (let k = 1; !(await connect()); k++) await sleep(rand() * Math.min(16_000, 1_000 * 2 ** (k - 1)));
Pick one

Go deeper

Pro tips
  1. Send the attempt number with every downstream call and count calls per original request at the bottom. A ratio well above 1 during an incident is retry amplification, visible before anyone reads the code. When: on the first dashboard of an overload incident (step 7).
  2. Fit the retries inside the caller's deadline. Before choosing attempts and a cap, add up the worst case: every attempt's timeout plus every backoff wait. If that sum passes the deadline the caller was given, the last retries run for nobody. When: setting a retry policy for a call that carries a deadline (step 3; the deadline itself is ds-partial-failure-timeouts step 10). Status: DOC; not run in this session.
Source
  • Marc Brooker, "Exponential Backoff And Jitter", AWS Architecture Blog, 4 March 2015: https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ · fetched 2026-09-29, saved as sources/brooker-2015.txt (sha256 ab167199…). "there are still clusters of calls. Instead of reducing the number of clients competing in every round, we've just introduced times when no client is competing" (step 4); "The solution isn't to remove backoff. It's to add jitter." (step 6); Equal Jitter "where we always keep some of the backoff and jitter by a smaller amount"; Decorrelated Jitter, where "we also increase the maximum jitter based on the last random value" (step 6). The article's formulas are images; their code is the next source. Valid as of 2026-09-29.
  • Brooker's simulator, aws-samples/aws-arch-backoff-simulator, src/backoff_simulator.py: https://github.com/aws-samples/aws-arch-backoff-simulator/blob/master/src/backoff_simulator.py · fetched 2026-09-29, saved as sources/brooker-simulator.txt. expo(n) = min(self.cap, pow(2, n)*self.base); equal v/2 + random.uniform(0, v/2); full random.uniform(0, v); decorrelated self.sleep = min(self.cap, random.uniform(self.base, self.sleep * 3)). lib/backoff.mjs implements these four (steps 3, 6). Valid as of 2026-09-29.
  • AWS Builders' Library, "Timeouts, retries, and backoff with jitter" (Marc Brooker): https://aws.amazon.com/builders-library/timeouts-retries-and-backoff-with-jitter/, which redirects to https://builder.aws.com/content/3EumjoZascWd1oZiEgL8ORlv3qE/timeouts-retries-and-backoff-with-jitter (page dated "Published Jun 12, 2026, Last modified Jun 15, 2026") · fetched 2026-09-29, saved as sources/builders-library.txt. "client errors should not be retried with the same request because they aren't going to succeed later", with the caveat that eventual consistency "significantly blurs this line" (step 1, hence "usually"); "APIs with side effects aren't safe to retry unless they provide idempotency" (step 2); "Now all of the clients are retrying constantly at the capped rate" (step 5); "If all the failed calls back off to the same time, they cause contention or overload again when they are retried" (step 4); "If each layer retries independently, the load on the database will increase 243x" and "our best practice is to retry at a single point in the stack" (steps 7–8); "limiting retries locally using a token bucket" (step 10). Valid as of 2026-09-29.
  • Google SRE book, "Handling Overload": https://sre.google/sre-book/handling-overload/ · fetched 2026-09-29, saved as sources/sre-handling-overload.txt. "A request will only be retried as long as this ratio is below 10%" (per-client retry budget, step 10); "requests should only be retried at the layer immediately above the layer that is rejecting them" and the "overloaded; don't retry" error (step 8). Valid as of 2026-09-29.

Checked against the tools and docs as of 2026-09-29.