Idempotency Design Patterns
Idempotency means performing an operation multiple times has the same effect as performing it once. In distributed systems, retries, and duplicate message consumption, idempotency prevents duplicate charges, duplicate orders, etc. This article covers implementations: unique key, state machine, token, deduplication table, with examples and a summary table.
Overview
- Unique key: Business-unique identifier (order id, payment id). Check before insert/update; if exists, ignore or return existing. Use DB unique index for enforcement.
- State machine: Operations have states (e.g. pending → paid → shipped). Execute only if the current state allows the operation; state transitions are idempotent. "Pay" when already paid returns success.
- Token: Client gets an idempotency token first; request carries it. Server checks if the token was used; if used, reject; if not, execute and mark used. Prevents duplicate submission.
- Deduplication table: Table keyed by request id (or business unique key). Check before insert; if exists, treat as duplicate. Add TTL or periodic cleanup.
Example
Example 1: Unique key
SQLCREATE UNIQUE INDEX uk_order_id ON orders(order_id); INSERT INTO orders (order_id, ...) VALUES (?, ...); -- Duplicate order_id violates unique constraint; treat as duplicate, return existing order
Example 2: State machine
Javaif (order.getStatus() != OrderStatus.PENDING_PAYMENT) { return order; // Already paid/cancelled; idempotent } order.setStatus(OrderStatus.PAID); orderRepository.save(order);
Example 3: Token
JavaString idempotencyKey = request.getHeader("Idempotency-Key"); if (idempotencyKey == null) return error("missing key"); if (processedKeys.contains(idempotencyKey)) return cachedResult; Result r = doProcess(request); processedKeys.put(idempotencyKey, r); return r;
Example 4: Pattern comparison
| Pattern | Best for | Notes |
|---|---|---|
| Unique key | Natural business identifier | Unique index; distinguish duplicate vs concurrent |
| State machine | Clear state flow | Complete states, atomic transitions |
| Token | Frontend duplicate submit, API | Storage and expiry policy |
| Deduplication table | Generic, no natural unique key | Periodic cleanup or TTL |
Core Mechanism / Behavior
- Unique key: DB unique constraint enforces at insert/update. On conflict, return existing or error; business treats as duplicate.
- State machine: Idempotency by state: only certain transitions allowed; repeat transitions are no-op.
- Token: One-time use; store token → result; reuse returns cached result.
- Atomicity: Use unique constraint + insert, or
SELECT FOR UPDATE+ state check + update to avoid concurrent duplicates.
Key Rules
- Writes and operations with side effects must be idempotent; reads are naturally idempotent.
- Prefer business unique keys (order id, payment id) when available; otherwise use token or deduplication table.
- Idempotency logic must be atomic to avoid duplicate execution under concurrency.
What's Next
See Message Idempotency and Payment Idempotency. See Distributed Transactions and Retry/Backoff for retry scenarios.