Class: SagaForge::CompensationRunner

Inherits:
Object
  • Object
show all
Defined in:
lib/saga_forge/compensation_runner.rb

Overview

Rollback is derived, not stored (§A.4): owed = processed events, mapped through the compensate: registry, deduped, run LIFO with a commit per compensation. Progress lives in context. A saga stuck in :compensating after exhausted retries is recovered by operator compensate! (Task 11) or the sweeper (Task 10).

Constant Summary collapse

COMP_ERROR_MESSAGE_LIMIT =
5_000

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(state) ⇒ CompensationRunner

Returns a new instance of CompensationRunner.



12
13
14
# File 'lib/saga_forge/compensation_runner.rb', line 12

def initialize(state)
  @state = state
end

Instance Attribute Details

#stateObject (readonly)

Returns the value of attribute state.



10
11
12
# File 'lib/saga_forge/compensation_runner.rb', line 10

def state
  @state
end

Instance Method Details

#callObject



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/saga_forge/compensation_runner.rb', line 16

def call
  definition = state.saga_definition

  loop do
    state.reload
    name = next_owed(definition)
    return finalize! if name.nil?

    entry_version = state.version
    begin
      outcome = run_one(definition, name, entry_version)
    rescue ConcurrencyConflict
      # Lost the race to another CompensationJob for this same instance
      # (defense-in-depth — limits_concurrency should make this rare in
      # practice). Nothing was written on this path: the raise happens
      # inside run_one's with_lock, before any update!, so no
      # comp_attempts/comp_error bookkeeping to unwind. Re-loop: reload
      # picks up the winner's committed progress, next_owed re-derives
      # against it, and we snapshot fresh before trying again.
      next
    end
    return outcome unless outcome == :continue
  end
end