Idempotency
Idempotency ensures that an operation can be safely retried without causing unintended side effects. In distributed systems—especially those involving network delays, retries, message brokers, or client-side reconnections—idempotency is a fundamental requirement for correctness and stability.
DIT requires all teams to design operations that are idempotent by default, particularly for any request or event that creates, updates, or deletes data.
Why Idempotency Is Required
Idempotency protects against:
- network retries
- duplicate messages from brokers
- client resubmissions (e.g., UI double-click, refresh)
- application restarts during processing
- race conditions in distributed workflows
- scenarios involving compensations or sagas
Without idempotency, systems risk producing:
- duplicate records
- inconsistent database states
- invalid external integrations
- double-charged payments
- diverging workflows across microservices
Idempotency in REST APIs
For all POST, PATCH, and DELETE requests, clients must include an Idempotency-Key header:
Idempotency-Key: <uuid>Service behavior:
- If the key has not been processed, execute the operation and store the result.
- If the key has been processed, return the previously stored response without re-executing the operation.
- Idempotency keys must be unique per client per endpoint.
- Idempotency keys must be stored in a database or Redis for a minimum TTL of 24 hours (unless service-specific requirements dictate longer retention).
Retrying a request must never produce a second side effect.
Idempotency in Event-Driven Systems
All event consumers must be idempotent. This means:
- Every event must have a unique event ID.
- Consumers must track processed event IDs.
- If an event with the same ID is received again, the consumer must skip processing the event.
This guarantees at-least-once delivery without causing multiple side effects.
Idempotency in Databases
Preferred implementation techniques include:
- Transactional Outbox Pattern
Ensures atomic writes and prevents duplicate event publication. - Unique constraints (e.g., unique transaction ID or idempotency key)
Prevents duplicates at the database level. - Optimistic Concurrency Control
Ensures resource changes only occur if the version matches. - Upsert patterns
Useful for create-or-update semantics.
When possible, the database must be the final authority ensuring uniqueness.
What Must Be Idempotent?
DIT requires idempotency for all operations that:
- create a resource
- update a resource
- trigger a workflow
- publish events
- perform external calls (e.g., payments)
- send SMS, email, or notifications
- modify system state (caches, queues, or other services)
If an operation cannot reasonably be made idempotent, the developer must consult the Head of Digital Development for approval and document the justification.
Common Implementation Patterns
Idempotency key tables
- Store request payload hash
- Store response
- Prevent reprocessing
Deduplication tables for events
- Track processed event IDs
- Apply TTL to prevent infinite growth
Database unique constraints
- Enforce structural idempotency
PUT semantics where applicable
- Updates entire resource, naturally idempotent
Summary
Idempotency is mandatory for ensuring reliability, correctness, and safety across distributed systems at DIT. Every request or event that can be replayed—intentionally or accidentally—must be handled in a way that guarantees the same outcome without producing repeated side effects.
