Idempotency Keys¶
Request-identity artifact — instantiates Asynchronous Replica Convergence
Attaches a caller-minted unique key to a logical operation so a retried request carries the same identity and can be recognized as the same operation, not a new one.
Idempotency Keys give each logical operation a stable, unique name that travels with the request, so that when a client retries after a timeout or dropped connection, the retry carries the same key and the receiver can tell it is the same operation rather than a second one. Its defining contribution is the identity itself — a caller-minted token, unique per intent — which is the hook every downstream dedup, guard, or ledger keys on. It supplies the name; it deliberately does not enforce what happens when the name repeats.
Example¶
A traveler taps "Confirm booking" in a hotel app on a flaky connection. The request reaches the server and creates reservation #A19 — but the response is lost, so the app, seeing no confirmation, retries. Because the app minted an idempotency key when the user first tapped — a UUID bound to that intent — and sent it on both attempts, the server recognizes the second request as the same booking and returns the existing reservation instead of booking a second room and charging twice. The key is the entire reason the retry is safe: without it, two identical requests are indistinguishable from two genuine bookings. Note what the key is tied to — the user's single intent to book — not to each network attempt, which is the distinction that makes it work.
How it works¶
The distinguishing property is a client-minted identity carried end to end:
- Mint once per intent. The client generates a unique key when the user forms the intent, not per network attempt, so every retry of that intent shares one key.
- Carry it on the wire. The key rides with the request (commonly a dedicated header), so it survives retries across the whole path.
- Record key → outcome. The receiver stores the key with the operation's result the first time it is seen.
- Return, don't repeat. A request bearing a known key returns the stored outcome instead of executing again.
Tuning parameters¶
- Key scope — per intent versus per attempt; this is the make-or-break dial — a key minted per attempt defeats the whole mechanism, since every retry looks new.
- Key lifetime — how long key→outcome mappings are retained; it must cover the longest realistic retry window, or a late retry re-executes.
- Who mints it — the client, or a gateway on the client's behalf; client-minted keys survive more of the path but require client cooperation.
- Payload binding — whether the key is bound to the request body, so reusing a key with different content is rejected rather than silently returning the old result.
- Collision resistance — how the key is generated (UUID, content hash); weak generation risks two distinct intents colliding onto one key.
When it helps, and when it misleads¶
Its strength is enormous leverage for a tiny artifact: a single stable token makes retries and network uncertainty safe, which is why "create"-style operations that are not naturally idempotent lean on it.[1] Its failure modes come from misuse of the identity, not the identity itself. A key minted per attempt makes every retry look new; a key reused across different intents causes the opposite error, suppressing a genuinely new operation as a duplicate; and a payload-unbound key can return a stale result for a changed request. The classic misuse is treating the key as the enforcement — but the key only names the operation; something downstream must actually act on the name. The discipline is to mint once per intent, bind the key to the payload, set a lifetime that outlives retries, and always pair the key with a consumer or guard that reads it.
How it implements the components¶
operation_identity_key— it is the operation identity: a stable, unique, on-the-wire name for one logical operation, minted at intent and preserved unchanged across every retry.
The key only names the operation; it does not enforce it. Turning that name into at-most-once effects (idempotence_guard, side_effect_boundary) is Deduplicating Message Consumer's work; a record's version_token and state_consistency_guard are Optimistic Concurrency Check's; and resolving a conflict once one is detected (conflict_resolution_rule) belongs to Data Diff and Merge Tool.
Related¶
- Instantiates: Asynchronous Replica Convergence — it supplies the operation identity that lets replayed and retried requests be recognized rather than re-applied.
- Sibling mechanisms: Deduplicating Message Consumer · Optimistic Concurrency Check · Event Sourcing with Commutative Handlers · Data Diff and Merge Tool
Notes¶
The key is an identity artifact, inert on its own — its entire value is in what reads it. Pair it with a Deduplicating Message Consumer on a stream, or a key→outcome store behind an API. And note the identity it carries names an operation; the superficially similar version_token of Optimistic Concurrency Check names a record's version — one answers "which request?", the other "which version of the data?".
References¶
[1] In HTTP an operation is idempotent when performing it many times has the same effect as performing it once; PUT and DELETE are defined that way, while POST is not — which is exactly why POST-style "create" operations are the ones that need an explicit idempotency key. ↩