Idempotency

SYSTEM DESIGN SERIES  ยท  TOPIC 17 OF 23+  ยท  part of the 16 โ†’ 17 โ†’ 18 chain
1. The Retry That Bills You Twice
Same duplicate request, same $50 charge - protected or not (looping)
No key: the client never got an ack, so it retries the exact same charge
No key: the server has no way to know it already did this once
No key: $50 becomes $100 - the retry was supposed to be safe, not costly
With a key: the retry carries the same idempotency key as the original
With a key: the server recognizes it, skips the work, replays the stored result
With a key: the client still gets its answer - the charge just doesn't happen twice
2. What Idempotent Actually Means
Doing it once or doing it five times looks the same
  • Formally: f(f(x)) = f(x) - applying it again changes nothing further
  • "Set balance to $100" - run it five times, still $100
  • "Add $50 to balance" - run it five times, that's $250 extra
  • The difference isn't the operation's name - it's whether repeats accumulate
๐Ÿ’ก Idempotent: flipping a switch to ON - flick it ten times, it's still just ON. Not idempotent: a doorbell - press it ten times, it rings ten times.
3. Idempotent vs Non-Idempotent
Idempotent
  • SET a value, DELETE a row
  • "Mark this notification as read"
  • Safe to retry blindly, forever
VS
Non-Idempotent
  • ADD to a value, append to a list
  • "Charge this card," "send this email"
  • Retrying blindly causes real damage
๐Ÿ” Retries are supposed to make things safer. Without idempotency, they make the risky ones worse.
4. HTTP Methods - Who Promises This
Part of the actual spec, not just convention
GET
Idempotent by spec. Reading never changes anything, however many times.
PUT
Idempotent by spec. "Replace this resource with X" - same X, same result.
DELETE
Idempotent by spec. Already gone stays gone - no error required.
POST
Not idempotent by spec. "Create a new one" - twice means two of them.
5. Idempotency Keys - The Practical Fix
Let the client label the attempt, not just the action
  • Client generates one unique key per logical attempt, sends it with every retry
  • Server stores key โ†’ result the first time it processes it
  • Seen that key before? Skip the work, replay the stored result
  • Needs an atomic check-and-store (a unique constraint, topic 13) or two concurrent duplicates can still both slip through
6. Where This Shows Up in Practice
Not just a payments trick
Payment APIs
(Stripe-style keys)
Any Retried API Call
Queue Consumers
(topic 16)
Job Schedulers
Anywhere a request might legitimately be sent more than once
If a network call can time out, it can be retried. If it can be retried, whatever it triggers needs to survive being triggered twice.
7. Designing For It
Add an idempotency key when:
โœ” The operation could plausibly be retried
โœ” Repeating it changes money, inventory, or state that accumulates
โœ” You're a consumer behind at-least-once delivery (topic 16)
Idempotency Turns "At Least Once" Into "Effectively Exactly Once"
Natural idempotency is enough when:
โœ” It's already a SET, not an ADD
โœ” It's already a DELETE, not an append
โœ” Repeats genuinely can't accumulate damage
๐Ÿ’ก Retries are also how a client can accidentally - or deliberately - overwhelm you. Controlling how many requests get in at all is Rate Limiting - topic 18, next.