Messaging and replay
Handling duplicate Kafka messages without duplicate business effects
By the BackendDrills editorial team · Published and checked October 6, 2026 · 7-minute read
Before you start: Transactions, operation identity and retries. Find this reading in a study path →
An idempotent Kafka producer does not automatically make a consumer's external business effects happen once. A consumer can commit an external write and crash before committing its offset, then receive the record again. Protect the effect at the system that owns it.
Write down the failure window
Imagine a warehouse projection that increments a received quantity. A worker saves the increment, then restarts before its offset commit. The record returns after reassignment. If the handler increments again, the business result is wrong even though Kafka is functioning as designed.
Illustrative sequence:
1. Read event receiving-confirmed, event_id=receipt-42
2. Commit warehouse quantity update
3. Process stops before offset commit
4. Another worker receives receipt-42
5. The handler must recognize that its effect already committed
Committing the offset before the database write creates the opposite problem: a crash can skip an unapplied effect. Decide whether replay is acceptable and where durable evidence of completion belongs before choosing the commit order.
Make deduplication and the effect atomic
For this example, use a durable event identity and a unique constraint scoped to the relevant tenant and operation. Insert the receipt and apply the quantity update within the same database transaction. Only after it commits should the consumer acknowledge progress. If an identical receipt already exists, confirm that it represents the same business event and acknowledge the replay without repeating the increment.
Illustrative transaction, not executable SQL:
BEGIN
insert receipt(tenant_id, event_id) under a unique constraint
if the receipt was newly inserted:
apply the warehouse quantity change
COMMIT
then commit consumer progress
The example assumes the receipt and quantity are in the same transactional database. A check followed by a separate insert is vulnerable to concurrent workers. A receipt committed separately from the effect can also claim success for work that never finished.
Know where Kafka transactions apply
Kafka transactions can coordinate consumed offsets with output records in Kafka. External destinations need their own cooperation. For a payment API or email delivery, examine the destination's idempotency contract, retention period and failure responses. An outbox can record intent atomically with a database change; it still needs a safe delivery and replay strategy.
Test more than a normal retry
| Test | Required outcome for this example |
|---|---|
| Replay after the database commit | Quantity changes once |
| Crash before transaction commit | No receipt without its effect |
| Two workers process the same identity | The unique constraint prevents a double effect |
| Same identity, different payload | Mismatch is investigated, not silently discarded |
Document how long event identities are retained and how historical replay works after that window. Monitor duplicate receipts and mismatches separately. A successful replay test demonstrates the stated warehouse invariant; it does not prove every downstream operation has exactly-once behavior.
Check the underlying behavior
Original illustrative examples, prepared with AI assistance and checked against the linked primary documentation. No customer incident or vendor endorsement is claimed. Our editorial approach.
Practice the next decision
Try a complete free backend drill: inspect evidence, make three decisions and review the reasoning. No account or card required.
Try a free incident drill →Selected practice from the study paths
- One event. Two shipments. · Complete free drill
- The order exists. The event does not. · Full edition drill
Free readings need no account. Full edition drills require verified access; opening a paid link does not expose its answers.