Technical
Idempotency Keys: The Distributed Systems Primitive Worth Learning
Distributed systems fail in boring ways: a timeout here, a retry there, a duplicate over yonder. Most of those problems collapse into one pattern if you use idempotency keys correctly. It is the single best ratio of simplicity to impact I know.
The Core Idea
An idempotency key is a unique identifier the client generates for an operation. The server records the key along with the result. If the client retries with the same key, the server returns the cached result instead of doing the work again.
That is it. The complexity is in the details, but the core is a dictionary from key to result.
Where It Matters
Any operation that costs money, sends a notification, or changes external state needs idempotency. Payment processing is the canonical example: you do not want to charge a card twice because the network blipped. But the same applies to sending emails, creating records, triggering webhooks, or running any expensive job.
The Minimal Implementation
def handle_request(key: str, operation: Callable) -> dict:
# Check if we have already processed this key
cached = idempotency_store.get(key)
if cached:
if cached['status'] == 'complete':
return cached['result']
if cached['status'] == 'in_progress':
raise HTTPException(409, 'Retry in progress')
# Mark as in progress
idempotency_store.set(key, {'status': 'in_progress'}, ttl=3600)
try:
result = operation()
idempotency_store.set(key, {'status': 'complete', 'result': result}, ttl=86400)
return result
except Exception as e:
idempotency_store.delete(key)
raiseDynamoDB with TTL is a perfect store for this. Redis with EXPIRE works equally well. The key is picking a TTL that is longer than any reasonable retry window but shorter than eternity.
The Client Responsibility
Clients generate the key. A UUID works. A content hash works. What matters is that the same logical operation always uses the same key. If the client generates a new key on every retry, idempotency is lost.
Stripe's API documented this pattern for the industry and their idempotency documentation is worth reading even if you never use Stripe. The primitive is language-agnostic and protocol-agnostic. Apply it anywhere you have retries and you will sleep better.
RELATED READING
The Consulting Shift I Am Making In Year Two
After a year of writing and building, my consulting practice is changing shape. Shorter engagements. Sharper outcomes.
ReadThe Frontend Shift: Shipping Less JavaScript In Year Two
A year ago I reached for Next.js for everything. This year I often reach for nothing.
ReadThe Serverless Lesson I Would Write On A Sticky Note
After a year of shipping serverless projects, one rule explains most of the wins and all of the losses.
Read