Skip to content

Core Concepts

Understand how idempotency ensures exactly-once execution.

What is Idempotency?

An operation is idempotent if executing it multiple times produces the same result as executing it once.

Idempotency Key

A unique identifier sent by the client to identify a specific operation.

Key Format

Idempotency-Key: <unique-identifier>

Good Key Examples

bash
# UUID v4 (recommended)
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000

# Prefixed UUID
Idempotency-Key: payment-550e8400-e29b-41d4

# User + Operation specific
Idempotency-Key: user-123-order-456-checkout

Bad Key Examples

bash
# Predictable/Sequential
Idempotency-Key: 1
Idempotency-Key: 2

# Timestamp only
Idempotency-Key: 1706123456789

# Too generic
Idempotency-Key: payment

Request Fingerprint

A hash of request content to detect misuse of idempotency keys.

Why Fingerprinting?

Prevents accidental key reuse with different data:

Request 1:
  Key: abc-123
  Body: {amount: 100}
  -> Fingerprint: xyz789
  -> Processed

Request 2 (Same key, different body!):
  Key: abc-123
  Body: {amount: 200}
  -> Fingerprint: def456
  -> Mismatch Error!

Record Lifecycle

Record States

StateDescriptionResponse to Duplicate
processingFirst request executingWait for completion
completedSuccess, response cachedReturn cached response
failedError occurredReturn stored error

Redis Data Model

Key: idempotency:{idempotency-key}
Value: {
  key: "abc-123",
  fingerprint: "sha256...",
  status: "completed",
  statusCode: 201,
  response: "{\"id\":456}",
  headers: "{\"Location\":\"/payments/456\"}",
  startedAt: 1706123456000,
  completedAt: 1706123457000
}
TTL: 86400 (24 hours)

Response Replay

When a duplicate request arrives, the cached response is replayed:

What Gets Replayed

ComponentReplayedNotes
Status codeYes201, 200, etc.
Response bodyYesJSON serialized
Specified headersYesIf configured
CookiesNoNot cached
TimingNoImmediate

Concurrent Requests

When two requests with the same key arrive simultaneously:

TTL and Expiration

Request at T=0
|
+-- Processing (lock held)
|   +-- Max: lockTimeout (30s)
|
+-- Completed at T=1s
|   +-- Response cached
|
+-- TTL expires at T+86400s
    +-- Record deleted
    +-- Key can be reused

Important

After TTL expires, the same idempotency key can be used for a NEW operation. Choose TTL wisely.

Next Steps

Released under the MIT License.