Class: CMDx::Idempotency
- Inherits:
-
Object
- Object
- CMDx::Idempotency
- Defined in:
- lib/cmdx/idempotency.rb
Overview
Declared via Task.idempotent_by. After inputs resolve, claims a shared
store slot and runs the retry_on loop inside that claim so duplicate
invocations with the same logical key short-circuit before work repeats.
Store keys are namespace:TaskName:segment (see StoreKey#compose). Values
move processing → completed after the wrapped block returns (including
output verification when invoked from Runtime); the key is deleted on
StandardError or non-success signals (skip! / fail!) so retries can
reclaim.
Constant Summary collapse
- PROCESSING =
"processing"- COMPLETED =
"completed"
Instance Attribute Summary collapse
-
#key ⇒ Object
readonly
Returns the value of attribute key.
Class Method Summary collapse
-
.disabled ⇒ Idempotency
Disabled configuration (no key).
Instance Method Summary collapse
-
#build(new_key, new_options) ⇒ Idempotency
Returns a new Idempotency layering
new_optionsonto the current one. - #condition_if ⇒ Symbol, ...
- #condition_unless ⇒ Symbol, ...
- #enabled? ⇒ Boolean
-
#initialize(key, options = EMPTY_HASH) ⇒ Idempotency
constructor
A new instance of Idempotency.
- #namespace ⇒ String
-
#on_duplicate ⇒ Symbol
:skipor:fail. -
#process(task) { ... } ⇒ Object
Runs the given block behind a store claim when #enabled? and gates pass.
- #ttl ⇒ Integer
Constructor Details
#initialize(key, options = EMPTY_HASH) ⇒ Idempotency
Returns a new instance of Idempotency.
41 42 43 44 |
# File 'lib/cmdx/idempotency.rb', line 41 def initialize(key, = EMPTY_HASH) @key = key @options = .freeze end |
Instance Attribute Details
#key ⇒ Object (readonly)
Returns the value of attribute key.
27 28 29 |
# File 'lib/cmdx/idempotency.rb', line 27 def key @key end |
Class Method Details
.disabled ⇒ Idempotency
Returns disabled configuration (no key).
21 22 23 |
# File 'lib/cmdx/idempotency.rb', line 21 def disabled DISABLED end |
Instance Method Details
#build(new_key, new_options) ⇒ Idempotency
Returns a new Idempotency layering new_options onto the current one.
When new_key is non-nil it replaces the resolver; when new_key is
nil, only options merge and the existing resolver is kept. A disabled
config stays disabled when only options are passed (a key is still required
to enable).
85 86 87 88 89 90 91 92 |
# File 'lib/cmdx/idempotency.rb', line 85 def build(new_key, ) return self if new_key.nil? && .empty? merged_key = new_key.nil? ? @key : new_key = @options.merge() self.class.new(merged_key, ) end |
#condition_if ⇒ Symbol, ...
62 63 64 |
# File 'lib/cmdx/idempotency.rb', line 62 def condition_if @options[:if] end |
#condition_unless ⇒ Symbol, ...
67 68 69 |
# File 'lib/cmdx/idempotency.rb', line 67 def condition_unless @options[:unless] end |
#enabled? ⇒ Boolean
72 73 74 |
# File 'lib/cmdx/idempotency.rb', line 72 def enabled? !key.nil? end |
#namespace ⇒ String
47 48 49 |
# File 'lib/cmdx/idempotency.rb', line 47 def namespace @options[:namespace] || "cmdx:idem" end |
#on_duplicate ⇒ Symbol
Returns :skip or :fail.
52 53 54 |
# File 'lib/cmdx/idempotency.rb', line 52 def on_duplicate @options[:on_duplicate] || :skip end |
#process(task) { ... } ⇒ Object
On duplicate keys, signals skip! or fail! on task — control
does not return to the caller of #process.
Runs the given block behind a store claim when #enabled? and gates pass.
Releases the claim on StandardError or a non-returning exit (skip!,
fail!) so retry_on can run work again; marks the slot completed
after the block returns successfully.
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/cmdx/idempotency.rb', line 107 def process(task) return yield unless enabled? return yield unless Util.satisfied?(condition_if, condition_unless, task) store_key = StoreKey.task_key(task, namespace:, resolver: key) return yield if store_key.nil? if Stores.set(store_key, PROCESSING, nx: true, ttl:) Telemetry.emit(task, :idempotency_claimed, idempotency_key: store_key) succeeded = false begin yield succeeded = true rescue StandardError Stores.del(store_key) raise ensure Stores.del(store_key) unless succeeded end mark_completed!(store_key, task) else duplicate!(task, store_key) end end |
#ttl ⇒ Integer
57 58 59 |
# File 'lib/cmdx/idempotency.rb', line 57 def ttl @options[:ttl] || 300 end |