I shall say this only once
And you shall do it only once. Exactly once. That’s a very common assumption for most of business software. One trigger equals one outcome. As it turns out, it is easier said than done.
One way to solve the problem is to prevent messages from getting duplicated in the fist place. This requires transactions spanning data stores and messaging systems which is neither fast nor widely available.
Another way is taking advantage of natural idempotency of some operations, e.g. setting a value. But let’s face it, most business code is more complex than that.
Right from the trenches, I’ll show you the Outbox pattern which makes distributed transaction look like a rusty old timer. Join me in this talk and make sure you’ll never refund a customer twice, again.
The Outbox records the IDs of processed messages so that duplicates are safely ignored. The outgoing messages are not dispatched immediately but first persisted along the business data to prevent ghost [ghost] messages. The Outbox pattern has low performance footprint (lower than a distributed transaction spanning a queue and a databse) and can be used with any type of data stores.