Module: Smith::Workflow::Claim
- Defined in:
- lib/smith/workflow/claim.rb
Overview
ActiveRecord-aware atomic claim helper. Two strategies:
.atomic — AASM-event path. SELECT FOR UPDATE + record.public_send(transition_via)
inside transaction_owner.transaction. AASM callbacks fire.
.cas — single-statement CAS via update_all + where(status: from_statuses).
Does NOT invoke AASM events; intended for non-AASM claim sites
that already use update_all today.
ActiveRecord is loaded lazily — this file does NOT const-reference ::ActiveRecord at module load. Both methods raise AdapterUnavailable before any other work when ::ActiveRecord is not defined.
Defined Under Namespace
Classes: AdapterUnavailable, UnexpectedStatus
Class Method Summary collapse
- .atomic(model_class, id:, from_statuses:, transition_via:, terminal_statuses: [], on_unexpected_status: :raise, transaction_owner: nil) ⇒ Object
- .cas(model_class, id:, from_statuses:, to_status:, status_column: :status, updated_at_column: :updated_at, now: -> { Time.now.utc }) ⇒ Object
Class Method Details
.atomic(model_class, id:, from_statuses:, transition_via:, terminal_statuses: [], on_unexpected_status: :raise, transaction_owner: nil) ⇒ Object
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/smith/workflow/claim.rb', line 29 def self.atomic(model_class, id:, from_statuses:, transition_via:, terminal_statuses: [], on_unexpected_status: :raise, transaction_owner: nil) ensure_active_record! validate_atomic_args!(model_class, transition_via) owner = transaction_owner || model_class from = Array(from_statuses).map(&:to_s) terminal = Array(terminal_statuses).map(&:to_s) claimed = false owner.transaction do locked = model_class.lock.find(id) status = locked.public_send(:status).to_s if from.include?(status) locked.public_send(transition_via) claimed = true elsif terminal.include?(status) claimed = false else handle_unexpected_status!(model_class, id, status, on_unexpected_status) claimed = false end end claimed ? model_class.find(id) : nil end |
.cas(model_class, id:, from_statuses:, to_status:, status_column: :status, updated_at_column: :updated_at, now: -> { Time.now.utc }) ⇒ Object
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/smith/workflow/claim.rb', line 59 def self.cas(model_class, id:, from_statuses:, to_status:, status_column: :status, updated_at_column: :updated_at, now: -> { Time.now.utc }) ensure_active_record! from = Array(from_statuses).map(&:to_s) updates = { status_column => to_status.to_s } updates[updated_at_column] = now.call if updated_at_column rows = model_class .where(:id => id, status_column => from) .update_all(updates) rows.zero? ? nil : model_class.find(id) end |