Class: AceMQ::AMQP::Patterns::InMemoryIdempotencyStore
- Inherits:
-
Object
- Object
- AceMQ::AMQP::Patterns::InMemoryIdempotencyStore
- Defined in:
- lib/acemq/amqp/patterns/idempotency.rb
Overview
An idempotency store that remembers keys in this process.
Right behind one worker, and wrong the moment there are two: each has its own memory, so both are told they are first and the duplicate goes through. It is also lost on restart, which turns every message in flight into a duplicate.
Use it in tests, and in a single-process service. Anything else wants a store the workers share — the same database the work is written to, in the same transaction, which is the only arrangement that actually holds.
Constant Summary collapse
- DEFAULT_WINDOW =
How long a key is remembered when no window is given.
3600.0
Instance Method Summary collapse
-
#claim(key) ⇒ Symbol
Claims a key, or says why not: done already, or still being done.
-
#confirm(key) ⇒ Object
Records that the claimed message really was handled, so a repeat is a duplicate rather than work in progress.
-
#first_time?(key) ⇒ Boolean
Records a key, and says whether it is new.
-
#forget(key) ⇒ Object
Removes a key, so the message it belongs to can be handled again.
-
#initialize(window: DEFAULT_WINDOW) ⇒ InMemoryIdempotencyStore
constructor
The window is also the claim's lease: a key claimed and never confirmed is in progress until it ages out, and then it is free again.
-
#size ⇒ Object
How many keys are remembered, for a test that wants to know the window is doing its job.
Constructor Details
#initialize(window: DEFAULT_WINDOW) ⇒ InMemoryIdempotencyStore
The window is also the claim's lease: a key claimed and never confirmed is in progress until it ages out, and then it is free again.
100 101 102 103 104 |
# File 'lib/acemq/amqp/patterns/idempotency.rb', line 100 def initialize(window: DEFAULT_WINDOW) @window = window.positive? ? window.to_f : DEFAULT_WINDOW @seen = {} @lock = Mutex.new end |
Instance Method Details
#claim(key) ⇒ Symbol
Claims a key, or says why not: done already, or still being done.
110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/acemq/amqp/patterns/idempotency.rb', line 110 def claim(key) key = key.to_s @lock.synchronize do now = Process.clock_gettime(Process::CLOCK_MONOTONIC) sweep(now) held = @seen[key] next held[1] ? Claim::DUPLICATE : Claim::IN_PROGRESS if held @seen[key] = [now, false] Claim::CLAIMED end end |
#confirm(key) ⇒ Object
Records that the claimed message really was handled, so a repeat is a duplicate rather than work in progress.
131 132 133 134 |
# File 'lib/acemq/amqp/patterns/idempotency.rb', line 131 def confirm(key) @lock.synchronize { @seen[key.to_s]&.[]=(1, true) } nil end |
#first_time?(key) ⇒ Boolean
Records a key, and says whether it is new.
127 |
# File 'lib/acemq/amqp/patterns/idempotency.rb', line 127 def first_time?(key) = claim(key) == Claim::CLAIMED |
#forget(key) ⇒ Object
Removes a key, so the message it belongs to can be handled again.
137 138 139 140 |
# File 'lib/acemq/amqp/patterns/idempotency.rb', line 137 def forget(key) @lock.synchronize { @seen.delete(key.to_s) } nil end |
#size ⇒ Object
How many keys are remembered, for a test that wants to know the window is doing its job.
144 |
# File 'lib/acemq/amqp/patterns/idempotency.rb', line 144 def size = @lock.synchronize { @seen.size } |