Stackbook Logo
data-consistency

Idempotency Patterns

Intent

Ensure that repeating an operation produces the same effect as executing it once.

Problem

Networks time out, clients retry, and brokers redeliver. Without idempotency, these normal behaviors cause duplicate charges, repeated emails, and corrupted state.

Forces

    Solution

    Idempotency Patterns

    Idempotency is the property that makes retries safe. Because distributed systems cannot distinguish a lost request from a lost response, any operation that might be repeated must be designed to tolerate repetition.

    How it works

    The client generates a unique key, often a UUID, for each logical action and sends it in a header. On first receipt, the server atomically records the key as in progress, performs the work, and stores the response with the key. A repeated request with the same key returns the stored response without redoing the work. If a duplicate arrives while the first is still running, it waits or receives a conflict response. Requests that reuse a key with a different payload are rejected as misuse.

    Implementation steps

    1. Identify non-idempotent operations that can be retried
    2. Define the key format, scope, and who generates it
    3. Persist key, request fingerprint, and result in the same transaction as the effect
    4. Handle in-flight duplicates with atomic insert or locks
    5. Reject key reuse with mismatched payloads
    6. Expire keys after a documented retention window

    Common pitfalls

    • Recording the key in a different transaction from the side effect
    • Generating a new key on every retry attempt
    • Scoping keys globally when they should be per user or endpoint
    • Forgetting that downstream calls need their own idempotency keys

    Metrics to watch

    • Duplicate request rate
    • Replayed response count
    • Key store size and expiry lag
    • Conflicts from in-flight duplicates
    • Duplicate side effects detected by reconciliation

    Example configuration

    -- Atomic idempotent processing
    BEGIN;
    INSERT INTO idempotency_keys (key, request_hash, status)
    VALUES (:key, :hash, 'in_progress')
    ON CONFLICT (key) DO NOTHING;
    -- if no row inserted, return stored response
    INSERT INTO payments (id, amount) VALUES (:id, :amount);
    UPDATE idempotency_keys SET status = 'done', response = :resp
    WHERE key = :key;
    COMMIT;
    

    Trade-offs and adoption

    Teams adopt this approach when operations are retried by clients, gateways, or brokers; payments, orders, and other non-repeatable effects are involved. It is a poor fit when operations are naturally idempotent reads, or when duplicates are harmless and cheaper to tolerate than to prevent. The central tensions are storage cost vs duplicate protection window; strict locking vs throughput; server-side deduplication vs client discipline. The main benefits are that it delivers: makes retries safe; tolerates at-least-once delivery; simplifies client error handling; prevents costly duplicate side effects. The main costs to budget for are: requires key storage and expiry management; concurrent duplicate requests need locking or atomic checks; hard to apply to external side effects; clients must generate stable keys. Governance typically looks like this: API standards mandate idempotency keys for non-safe operations. Expect adoption cost to be low to medium: storage and API conventions, and a best fit for any team building networked or event-driven services. Critics point out that key scoping and expiry mistakes silently permit duplicates, and that idempotency of internal state does not extend to third-party side effects. Treat these concerns as design inputs, and revisit the decision as traffic, team size, and failure history change.

    Key takeaways

    • Assume every request may arrive more than once
    • Commit the key and the effect together
    • Reuse the same key across retries of one action
    • Propagate keys to downstream dependencies

    ✓ When to Use

    • •Operations are retried by clients, gateways, or brokers
    • •Payments, orders, and other non-repeatable effects are involved
    • •At-least-once message delivery is in use
    • •Workflows resume after partial failure

    ✗ When Not to Use

    • •Operations are naturally idempotent reads
    • •Duplicates are harmless and cheaper to tolerate than to prevent
    • •The system can guarantee exactly-once through a single transactional store

    Pros

    • +Makes retries safe
    • +Tolerates at-least-once delivery
    • +Simplifies client error handling
    • +Prevents costly duplicate side effects

    Cons

    • −Requires key storage and expiry management
    • −Concurrent duplicate requests need locking or atomic checks
    • −Hard to apply to external side effects
    • −Clients must generate stable keys

    Cost Profile

    Infrastructure

    Operational

    Cognitive

    Failure Modes

      Alternatives

        Related Patterns

          Competency Domains

          data statedistribution communicationreliability ops