Module: AceMQ::AMQP::Patterns::IdempotencyStore

Defined in:
lib/acemq/amqp/patterns/idempotency.rb

Overview

Remembers which messages have already been handled.

A store is anything answering two methods:

first_time?(key)  # records the key, true when it had not been seen
forget(key)       # removes it, so a message that failed can be redone

and, optionally, two more:

confirm(key)      # the work is done; start remembering it properly
claim(key)        # first_time? with a three-way answer, see {Claim}

A store with claim can tell work in progress from work done, and idempotent puts the first back rather than accepting it. A store with only first_time? cannot, and is treated as before: a repeat is a duplicate.

first_time? has to be atomic. Two consumers handed the same message at the same moment must not both be told they are first, or the guard has done nothing except cost a round trip.

confirm is what a store needs when its record outlives the process that made it. InMemoryIdempotencyStore has no use for one — a crash wipes it, so a key it holds is a key somebody is working on now. A store in a database has to tell the two apart, because a key left behind by a consumer that died has to expire and a key left behind by work that finished must not. SQLIdempotencyStore answers it; a store that does not is simply never asked.

A duck type rather than a class to inherit from, because the store somebody actually wants is their own database — ideally the very rows the handler writes, in the same transaction — and asking them to subclass something from a messaging library to get there is asking for the wrong thing.