Inbox Pattern

The Inbox Pattern records consumed message identifiers in the same database transaction as the business update. This lets a consumer detect and ignore duplicate deliveries when a message broker provides at-least-once delivery.

An inbox table belongs to the consumer side of an asynchronous workflow. When a message arrives, the consumer stores its unique message ID and applies the related business change within one database transaction.

If the same message is delivered again, the consumer finds its ID in the inbox table and skips the business operation. This is useful because a consumer can successfully commit its database work and still fail before acknowledging the message to the broker.

The key requirement is atomicity: recording the message ID and changing business data must commit or roll back together. A unique constraint on the message ID provides a database-enforced guard against concurrent or repeated processing.

The pattern does not make the broker exactly-once. It makes the database-side handling idempotent for messages whose identifiers are recorded. The consumer still needs sensible retry, acknowledgment, and error-handling behavior.

Key points

Interview questions

How would you design an inbox table?

A basic design needs a unique message identifier, usually along with metadata such as consumer or message type when identifiers are not globally unique. The message ID should have a database uniqueness constraint. Depending on the system, timestamps and processing metadata can help with operations and retention. The inbox row should participate in the same transaction as the business change.

Does the Inbox Pattern provide exactly-once processing?

Not in the general distributed-systems sense. It can make a particular database transaction effectively duplicate-safe when the message ID and business update are handled atomically. External side effects, such as sending an email or calling another service, may still happen more than once unless they have their own idempotency mechanism. Therefore, the pattern is better described as durable deduplication at the consumer boundary.

What problem does the Inbox Pattern solve?

It helps a message consumer handle duplicate deliveries safely. A broker may deliver a message again when an acknowledgment is lost or processing is retried. The consumer stores the message ID and checks whether it has already been handled. If it has, the business operation can be skipped.

Why should the inbox insert and business update use the same transaction?

They need to represent one atomic unit of work. If the business update commits but the inbox insert does not, a retry may apply the business change again. If the inbox insert commits but the business update rolls back, a retry could be incorrectly treated as already processed. A single transaction prevents these two states.