Member-only story
Handle Duplicate Messages With Idempotent Consumers | Clean Architecture in .NET 8
Your message broker retries. Your consumer runs twice. Your order gets placed twice.
That is not a hypothetical. RabbitMQ, Azure Service Bus, Kafka — they all have at-least-once delivery guarantees. Network blips, app crashes, and deployment restarts mean your consumer will see the same message more than once. If your handler is not idempotent, you will corrupt data.
This article shows you a clean, production-proven pattern to make any MediatR command handler idempotent using an Outbox-style processed-messages table. You get the full code, layer by layer, inside a Clean Architecture solution targeting .NET 8.
If this kind of practical .NET architecture content is useful to you, consider following for more articles like this.
TL;DR
Every incoming message carries a unique MessageId. Before processing, check whether that ID has already been stored in a ProcessedMessages table. If it has, skip. If it has not, process and record the ID atomically. One pipeline behavior wires this up for every command — zero per-handler code.
The Problem in Plain Terms
At-least-once delivery means the broker guarantees the message reaches a consumer, but it does not guarantee…