Class: RubyReactor::StepSweeper
- Inherits:
-
Object
- Object
- RubyReactor::StepSweeper
- Defined in:
- lib/ruby_reactor/step_sweeper.rb
Overview
Re-dispatches async_step units whose job was lost.
An async_step is the one dispatched unit with no context of its own, so
neither Sweeper (top-level contexts) nor Map::Sweeper (map elements) can see
it. All it leaves behind is a Step Result Record stuck at dispatched, and
because that record is also the re-attach marker, already_dispatched?
actively refuses to dispatch again — so without this sweep a lost unit strands
its parent forever, re-parking on every recovery of the parent itself.
Liveness is the async_step: lock StepWorker holds for the life of the unit,
mirroring how Sweeper reads async: and Map::Sweeper reads map_element:. A
duplicate that races a live worker loses that lock and drops itself, so a
mis-judged unit re-runs its body at most once.
Constant Summary collapse
- DEFAULT_LIMIT =
1000- DISPATCH_KEYS =
The re-dispatch arguments, which the record carries verbatim because its key names the reactor that owns the step rather than the root the worker must load. Records written before recovery existed lack them and are skipped.
%w[root_context_id reactor_class_name step_context_id step_name].freeze
Class Method Summary collapse
Instance Method Summary collapse
-
#initialize(storage: nil, async_router: nil, logger: nil) ⇒ StepSweeper
constructor
A new instance of StepSweeper.
-
#run_once(limit: DEFAULT_LIMIT) ⇒ Object
Scans stored Step Result Records and re-dispatches the dispatched-but-dead ones.
Constructor Details
#initialize(storage: nil, async_router: nil, logger: nil) ⇒ StepSweeper
Returns a new instance of StepSweeper.
29 30 31 32 33 |
# File 'lib/ruby_reactor/step_sweeper.rb', line 29 def initialize(storage: nil, async_router: nil, logger: nil) @storage = storage || RubyReactor.configuration.storage_adapter @async_router = async_router || RubyReactor.configuration.async_router @logger = logger || RubyReactor.configuration.logger end |
Class Method Details
.run_once(limit: DEFAULT_LIMIT) ⇒ Object
25 26 27 |
# File 'lib/ruby_reactor/step_sweeper.rb', line 25 def self.run_once(limit: DEFAULT_LIMIT) new.run_once(limit: limit) end |
Instance Method Details
#run_once(limit: DEFAULT_LIMIT) ⇒ Object
Scans stored Step Result Records and re-dispatches the dispatched-but-dead ones. Returns the number re-dispatched.
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/ruby_reactor/step_sweeper.rb', line 37 def run_once(limit: DEFAULT_LIMIT) redispatched = 0 @storage.scan_step_results(count: limit).each do |record| next unless record["status"] == "dispatched" arguments = dispatch_arguments(record) next unless arguments next if live?(arguments) @async_router.perform_step_async(**arguments) redispatched += 1 rescue StandardError => e # One bad record must not abort the whole sweep. @logger.warn("RubyReactor::StepSweeper failed to re-dispatch #{record["step_name"]}: #{e.class}: #{e.message}") end redispatched end |