Tool

How long must the keys live?

Retry counts multiply rather than add, and the retry that causes the duplicate charge usually arrives on Monday morning from a person, not on Tuesday afternoon from a library. This works out both numbers.

Part one: the automatic retries

Every layer that retries multiplies the layer beneath it. Enter what each one is configured to do, not what anyone believes it does; these values are usually in three different repositories owned by three teams.

s
s
s
Worst-case attempts
27
For one business intent
Longest automatic path
2.1 h
Every layer exhausting its budget
27 attempts for one intent. If any operation in that path is not idempotent, that is 27 chances to perform it more than once, and every individual layer is inside its own limit.
Part two: the paths nobody counts

These are the retries that arrive days later, and they are where the duplicate charges live. A window sized for the automatic path has long since expired by the time somebody reruns Monday's failed batch.

h
From the operation failing to somebody draining the queue.
h
Friday evening failure, Monday morning rerun is 72 hours.
Consider a restore from backup
If a restore can replay a queue, it belongs in the window.
h
What your store is configured to keep.
x
PathDelay before a duplicate can arriveWhat it isYour window
Automatic retries2.1 hevery layer exhausting its budgetcovered
Dead-letter replay26 hafter the automatic path gives upnot covered
Operator rerun3.0 dayssomebody reruns the failed batchnot covered
Longest path
3.0 days
Operator rerun
Required window
6.0 days
Longest path x 2.0
Your window
24 h
Too short
Your 24 h window does not cover operator rerun at 3.0 days. A retry arriving after it expires is processed as a new operation, correctly, and the effect happens twice.
This calculator runs entirely in your browser. Nothing you type is sent anywhere unless you ask for the result by email at the bottom of the page.
Send me this window

Your retry configuration goes with it. If the layers multiply to a number nobody on the team could have stated from memory, that is usually worth a conversation on its own.

Your inputs are included so the reply can be specific.

Attempts for one intent, by retry layers

What a single business action can become once every layer has taken its turn. Each row is how many layers retry; each column is how many attempts each layer makes. Every one of these systems is correctly configured and every individual limit is respected.

Retrying layers2 attempts each3 attempts each4 attempts each5 attempts each
1 layer2345
2 layers491625
3 layers82764125
4 layers1681256625

Amber is 16 attempts or more, red is 64 or more. A typical stack has three retrying layers before anyone counts the queue consumer, the API gateway or the client's own retry, so the realistic row is usually lower than the real one.

A worked example

A payments service with three retrying layers, each configured to three attempts: the HTTP client at two seconds, the calling service at one minute, the job scheduler at one hour. Deduplication records are kept for 24 hours, which comfortably covers the automatic path.

The automatic path exhausts in just over two hours, so a 24-hour window looks generous, and for two years it is. That is 27 attempts for one intent, which nobody has ever written down, but every one of them carries the same key and the window holds.

Then a Friday evening deploy fails a batch. Nobody is on call for a non-urgent job, so it is rerun at 9am Monday: 72 hours later. The keys expired 48 hours before that. Every payment in the batch is processed as new, correctly, by a system with a working idempotency implementation.

The required window is 72 hours times a safety factor, so six days rather than one. The fix is a configuration change and a slightly larger table. The cost of not making it is a duplicate charge for every item in a failed batch, discovered by customers, in a system everybody believed was protected.

The arithmetic, so you can check it

Attempts are the product across layers: attempts per layer, multiplied, because each outer retry replays the entire budget beneath it. The automatic delay follows the same nesting, computed from the inside out: a layer contributes backoff x (attempts - 1) for its own retries, plus the whole inner path once per attempt.

The window is then the longest path of any kind, automatic or human, multiplied by a safety factor. Human paths are not modelled as retries because they are not: they are a delay with a person at the end of it, and the only number that matters is how long it can be.

The honest limit

This computes what your configuration permits, not what your traffic does. A window sized from it is correct and possibly generous. What it cannot tell you is whether deduplication sits at the boundary that performs the irreversible effect: a key kept for a month at the API gateway protects nothing if the ledger write happens twice underneath it. Check where the effect occurs before you trust the number.

The four properties an idempotency key needs are in idempotency for money movement, and what it does not solve in durable execution, idempotency, or both.

Questions

How long should idempotency keys be kept?

Longer than the longest retry path in the entire system, including the ones nobody counts: dead-letter replays, operator reruns of a failed batch, and restores from backup that replay a queue. Those arrive days after a window sized for automatic retries has expired, and the system then processes the operation as new, correctly by its own rules, and the effect happens twice.

Why do retry counts multiply instead of add?

Because each outer layer re-runs the entire budget beneath it. An HTTP client retrying three times inside a service retrying three times inside a scheduler retrying three times is twenty-seven attempts for one business intent, and every individual layer is correctly inside its own limit. Nothing is violated and nothing alerts.

What is the longest retry path in a typical system?

Almost never the automatic one. A Friday evening failure rerun on Monday morning is 72 hours, and a restore from backup can replay a queue a week later. Those two dominate every automatic path, and they are the ones that never appear in a retry configuration because they are a person rather than a setting.

Where should deduplication actually happen?

At the last boundary that can still cause the effect twice. If the effect is a ledger write, the ledger enforces uniqueness on the key. If it is a call to an external processor, the key is passed through rather than consumed by your service. Deduplicating at the API boundary protects against two API calls, not against one call whose downstream effect is applied twice.

Is a long deduplication window expensive?

Rarely, and the comparison is the point. A key and a stored result per operation for a week is a small table by any measure, set against a duplicate payment and the investigation that follows it. If the required window feels uncomfortably long, that discomfort is information about your retry architecture rather than about your storage bill.