Stackbook Logo
messagingestablished · medium operational burden

Idempotent Receiver

Also known as: idempotency-key, deduplication-receiver

Intent

Make a consumer or API safely handle duplicate requests or messages so repeated delivery has the effect of one.

Problem

Retries, at-least-once brokers and network timeouts cause the same request to arrive more than once. Without protection, duplicates create double charges, duplicate orders or repeated side effects.

Forces

  • •At-least-once delivery is the practical default
  • •Clients retry when they do not see a response
  • •Dedup state must be durable and bounded
  • •Check and effect must be atomic

Solution

Overview

An idempotent receiver ensures that processing the same request twice has the same outcome as processing it once. It is the standard defence against the duplicates that retries and at-least-once delivery inevitably produce.

How it works

The client generates a unique key per logical operation and reuses it on every retry. The server records the key with the outcome.

POST /payments
Idempotency-Key: 7f3a-91c2

BEGIN;
  INSERT INTO idempotency(key, request_hash) VALUES ('7f3a-91c2', 'h1')
    -- unique constraint; conflict means duplicate
  perform charge, store response
COMMIT;

If the insert conflicts, the server loads the stored response and returns it. If the key exists with a different request hash, it returns 422. For message consumers, the key is the message id, and the dedup record is written in the same database transaction as the state change, so a crash cannot separate them.

Pitfalls

  • Check-then-act races. Use a unique constraint or lock, not a plain read followed by an insert.
  • Storing the key outside the effect transaction, which loses atomicity when calling external systems; pass the key downstream too.
  • Short retention. Keep keys longer than the longest retry or redelivery window.
  • Server-generated keys. The client must create the key, otherwise retries get new ones.
  • In-flight duplicates. Return a conflict or wait while the first attempt is still processing.

Key takeaways

  • Client supplies a stable key; server stores key and result atomically.
  • Use unique constraints to resolve concurrent duplicates.
  • Retain keys beyond the retry horizon and validate payload equality.

✓ When to Use

  • •Payments and any non-idempotent POST operations
  • •Consumers of at-least-once message brokers
  • •Webhook handlers and retried API calls

✗ When Not to Use

  • •Operations already naturally idempotent such as PUT of full state
  • •Pure reads
  • •Cases where duplicates are harmless and cheap

Pros

  • +Safe retries for clients
  • +Enables at-least-once delivery with effectively-once results
  • +Clear semantics for support and audits

Cons

  • −Needs durable key storage and cleanup
  • −Adds a lookup to every request
  • −Concurrent duplicates need locking or unique constraints

Cost Profile

Infrastructure

Low - one table or cache

Operational

Medium - retention and cleanup jobs

Cognitive

Medium - atomicity subtleties

Failure Modes

  • Race lets two concurrent duplicates both execute

  • Key expires before a late retry arrives

  • Key stored without the effect, or the effect without the key, after a crash

Real-World Examples

Alternatives

    Related Patterns

    • webhook

    Competency Domains

    data statereliability ops