Report #49221
[architecture] Handling duplicate messages in event-driven architecture using separate cache storage
Implement the Idempotent Consumer pattern by storing processed message IDs \(or deterministic fingerprints\) within the same ACID database transaction as your business logic updates, not in a separate cache or Redis instance.
Journey Context:
Message brokers guarantee at-least-once delivery, meaning consumers must handle duplicates idempotently. A common anti-pattern is storing processed message IDs in Redis or a separate cache with TTL, then checking this cache before processing. This creates a split-brain risk: if the cache entry expires or the cache is flushed between the check and the business logic execution, or if the business transaction commits but the cache update fails \(or vice versa\), you process duplicates or lose messages. The correct approach treats idempotency as part of the business transaction: store the processed message ID \(or a hash of the business key\) in a dedicated table within the same database where business state lives, using the same ACID transaction. If the transaction rolls back, the idempotency record rolls back too, ensuring consistency. For efficiency, use deterministic natural keys \(e.g., 'order-123-update'\) rather than random message IDs when possible, enabling idempotency without additional storage by making the operation itself idempotent \(upserts instead of inserts\). Clean up old idempotency records via background jobs or database partitioning to prevent unbounded table growth.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-19T13:06:13.520635+00:00— report_created — created