Module: RubyReactor
- Defined in:
- lib/ruby_reactor.rb,
lib/ruby_reactor/lock.rb,
lib/ruby_reactor/step.rb,
lib/ruby_reactor/rspec.rb,
lib/ruby_reactor/period.rb,
lib/ruby_reactor/worker.rb,
lib/ruby_reactor/context.rb,
lib/ruby_reactor/reactor.rb,
lib/ruby_reactor/sweeper.rb,
lib/ruby_reactor/version.rb,
lib/ruby_reactor/web/api.rb,
lib/ruby_reactor/executor.rb,
lib/ruby_reactor/registry.rb,
lib/ruby_reactor/semaphore.rb,
lib/ruby_reactor/error/base.rb,
lib/ruby_reactor/middleware.rb,
lib/ruby_reactor/rate_limit.rb,
lib/ruby_reactor/dsl/reactor.rb,
lib/ruby_reactor/map/helpers.rb,
lib/ruby_reactor/map/sweeper.rb,
lib/ruby_reactor/step_worker.rb,
lib/ruby_reactor/sweeper_job.rb,
lib/ruby_reactor/async_waiter.rb,
lib/ruby_reactor/dsl/lockable.rb,
lib/ruby_reactor/ordered_lock.rb,
lib/ruby_reactor/step_signals.rb,
lib/ruby_reactor/step_sweeper.rb,
lib/ruby_reactor/configuration.rb,
lib/ruby_reactor/map/collector.rb,
lib/ruby_reactor/retry_context.rb,
lib/ruby_reactor/rspec/helpers.rb,
lib/ruby_reactor/step/map_step.rb,
lib/ruby_reactor/template/base.rb,
lib/ruby_reactor/map/dispatcher.rb,
lib/ruby_reactor/open_telemetry.rb,
lib/ruby_reactor/rspec/matchers.rb,
lib/ruby_reactor/template/input.rb,
lib/ruby_reactor/template/value.rb,
lib/ruby_reactor/dsl/map_builder.rb,
lib/ruby_reactor/storage/adapter.rb,
lib/ruby_reactor/template/result.rb,
lib/ruby_reactor/validation/base.rb,
lib/ruby_reactor/web/application.rb,
lib/ruby_reactor/dependency_graph.rb,
lib/ruby_reactor/dsl/async_macros.rb,
lib/ruby_reactor/dsl/step_builder.rb,
lib/ruby_reactor/error/undo_error.rb,
lib/ruby_reactor/interrupt_result.rb,
lib/ruby_reactor/template/element.rb,
lib/ruby_reactor/middleware_runner.rb,
lib/ruby_reactor/step/compose_step.rb,
lib/ruby_reactor/context_serializer.rb,
lib/ruby_reactor/map/result_summary.rb,
lib/ruby_reactor/rspec/test_subject.rb,
lib/ruby_reactor/dsl/compose_builder.rb,
lib/ruby_reactor/rate_limit_registry.rb,
lib/ruby_reactor/retry_queued_result.rb,
lib/ruby_reactor/rspec/storage_reset.rb,
lib/ruby_reactor/dsl/template_helpers.rb,
lib/ruby_reactor/map/element_executor.rb,
lib/ruby_reactor/utils/code_extractor.rb,
lib/ruby_reactor/dsl/interrupt_builder.rb,
lib/ruby_reactor/map/result_enumerator.rb,
lib/ruby_reactor/rspec/sidekiq_helpers.rb,
lib/ruby_reactor/storage/configuration.rb,
lib/ruby_reactor/storage/redis_adapter.rb,
lib/ruby_reactor/storage/redis_locking.rb,
lib/ruby_reactor/storage/redis_pub_sub.rb,
lib/ruby_reactor/dsl/validation_helpers.rb,
lib/ruby_reactor/error/dependency_error.rb,
lib/ruby_reactor/error/validation_error.rb,
lib/ruby_reactor/executor/graph_manager.rb,
lib/ruby_reactor/executor/retry_manager.rb,
lib/ruby_reactor/executor/step_executor.rb,
lib/ruby_reactor/adapters/sidekiq/router.rb,
lib/ruby_reactor/adapters/sidekiq/worker.rb,
lib/ruby_reactor/executor/result_handler.rb,
lib/ruby_reactor/step/async_reactor_step.rb,
lib/ruby_reactor/template/dynamic_source.rb,
lib/ruby_reactor/error/compensation_error.rb,
lib/ruby_reactor/error/step_failure_error.rb,
lib/ruby_reactor/executor/input_validator.rb,
lib/ruby_reactor/rspec/active_job_helpers.rb,
lib/ruby_reactor/rspec/async_test_helpers.rb,
lib/ruby_reactor/utils/backtrace_location.rb,
lib/ruby_reactor/dsl/async_reactor_builder.rb,
lib/ruby_reactor/dsl/interrupt_step_config.rb,
lib/ruby_reactor/rspec/step_executor_patch.rb,
lib/ruby_reactor/validation/schema_builder.rb,
lib/ruby_reactor/adapters/active_job/compat.rb,
lib/ruby_reactor/adapters/active_job/router.rb,
lib/ruby_reactor/adapters/active_job/worker.rb,
lib/ruby_reactor/error/async_result_pending.rb,
lib/ruby_reactor/error/deprecated_dsl_error.rb,
lib/ruby_reactor/error/schema_version_error.rb,
lib/ruby_reactor/storage/redis_reactor_scan.rb,
lib/ruby_reactor/storage/redis_step_results.rb,
lib/ruby_reactor/validation/input_validator.rb,
lib/ruby_reactor/error/deserialization_error.rb,
lib/ruby_reactor/web/coordination_serializer.rb,
lib/ruby_reactor/adapters/sidekiq/step_worker.rb,
lib/ruby_reactor/error/input_validation_error.rb,
lib/ruby_reactor/executor/async_step_dispatch.rb,
lib/ruby_reactor/error/context_too_large_error.rb,
lib/ruby_reactor/executor/compensation_manager.rb,
lib/ruby_reactor/executor/ordered_lock_support.rb,
lib/ruby_reactor/max_retries_exhausted_failure.rb,
lib/ruby_reactor/storage/redis_ordered_locking.rb,
lib/ruby_reactor/error/async_wait_timeout_error.rb,
lib/ruby_reactor/adapters/active_job/step_worker.rb,
lib/ruby_reactor/adapters/sidekiq/sweeper_worker.rb,
lib/ruby_reactor/adapters/active_job/sweeper_worker.rb,
lib/ruby_reactor/adapters/sidekiq/map_element_worker.rb,
lib/ruby_reactor/adapters/sidekiq/map_collector_worker.rb,
lib/ruby_reactor/adapters/active_job/map_element_worker.rb,
lib/ruby_reactor/adapters/active_job/map_collector_worker.rb,
sig/ruby_reactor.rbs
Defined Under Namespace
Modules: Adapters, Dsl, Error, Map, Period, RSpec, Step, StepSignals, Storage, SweeperJob, Template, Utils, Validation, Web, Worker Classes: AsyncWaiter, Configuration, Context, ContextSerializer, DependencyGraph, DispatchResult, Executor, Failure, Halt, InterruptResult, Lock, MaxRetriesExhaustedFailure, Middleware, MiddlewareRunner, OpenTelemetry, OrderedLock, RateLimit, RateLimitRegistry, Reactor, Registry, RetryContext, RetryQueuedResult, Semaphore, Skipped, StepSweeper, StepWorker, Success, Sweeper
Constant Summary collapse
- VERSION =
"0.7.1"
Class Method Summary collapse
- .async_reactor_channel(execution_id) ⇒ Object
-
.async_step_channel(context_id, step_name) ⇒ Object
The name under which a reactor class's durable state is keyed in storage (
reactor:<name>:context:<id>, map metadata, etc.). -
.async_step_lock_key(context_id, step_name) ⇒ Object
Liveness lock for one dispatched
async_step. - .configuration ⇒ Object
- .configure {|Configuration.instance| ... } ⇒ Object
- .Failure(error, **kwargs) ⇒ Object
-
.Halt(reason: nil, **kwargs) ⇒ Object
Build a
Haltresult. - .inferred_sweeper_job_class(router) ⇒ Object
- .internal_lib_path ⇒ Object
- .reactor_storage_name(reactor_class) ⇒ Object
- .root ⇒ Object
-
.Skipped ⇒ Object
Build a
Skippedresult. -
.start_sweeper! ⇒ Object
Kick the self-rescheduling recovery sweeper chain.
-
.Success(value = nil) ⇒ Object
Global helper methods.
-
.sweep_once(limit: nil) ⇒ Object
Run both recovery sweepers exactly once and return their counts.
-
.sweeper_job_class ⇒ Object
The sweeper job class living alongside the configured
async_router(e.g.Adapters::Sidekiq::Router->Adapters::Sidekiq::SweeperWorker), so the chain is kicked through whichever backend is configured instead of a hardcoded Sidekiq class. - .sweeper_job_class_error(router) ⇒ Object
Class Method Details
.async_reactor_channel(execution_id) ⇒ Object
410 411 412 |
# File 'lib/ruby_reactor.rb', line 410 def self.async_reactor_channel(execution_id) "rr:done:#{execution_id}" end |
.async_step_channel(context_id, step_name) ⇒ Object
The name under which a reactor class's durable state is keyed in storage
(reactor:<name>:context:<id>, map metadata, etc.). MUST be stable across
processes: the enqueuing process writes the blob under this name and a
different worker process reads it back by the same name. So an anonymous
class falls back to a fixed constant, NOT object_id — object_id is
process-local and would make the worker's read key miss the writer's key.
The context_id in the key still disambiguates distinct anonymous reactors.
(A truly anonymous class can't be reconstituted by name in another process,
so cross-process resume of one is inherently unsupported; this only keeps
the keys self-consistent within a process — e.g. inline tests.)
Completion-signal channels for the notified wait. One place, because
the publishing side and the waiting side must agree exactly and they live in
different files (StepWorker / Executor vs Template::Result).
406 407 408 |
# File 'lib/ruby_reactor.rb', line 406 def self.async_step_channel(context_id, step_name) "rr:done:#{context_id}:#{step_name}" end |
.async_step_lock_key(context_id, step_name) ⇒ Object
Liveness lock for one dispatched async_step. Held by StepWorker for the
life of the unit, so StepSweeper can tell a slow unit from a lost job.
416 417 418 |
# File 'lib/ruby_reactor.rb', line 416 def self.async_step_lock_key(context_id, step_name) "async_step:#{context_id}:#{step_name}" end |
.configuration ⇒ Object
389 390 391 |
# File 'lib/ruby_reactor.rb', line 389 def self.configuration Configuration.instance end |
.configure {|Configuration.instance| ... } ⇒ Object
385 386 387 |
# File 'lib/ruby_reactor.rb', line 385 def self.configure yield(Configuration.instance) if block_given? end |
.Failure(error, **kwargs) ⇒ Object
369 370 371 |
# File 'lib/ruby_reactor.rb', line 369 def self.Failure(error, **kwargs) Failure.new(error, **kwargs) end |
.Halt(reason: nil, **kwargs) ⇒ Object
Build a Halt result. Return one from a step's run block to halt the
reactor cleanly without triggering compensation of previous steps.
375 376 377 |
# File 'lib/ruby_reactor.rb', line 375 def self.Halt(reason: nil, **kwargs) Halt.new(reason: reason, **kwargs) end |
.inferred_sweeper_job_class(router) ⇒ Object
455 456 457 458 459 460 461 462 |
# File 'lib/ruby_reactor.rb', line 455 def self.inferred_sweeper_job_class(router) namespace_name = router.name.to_s.rpartition("::").first raise sweeper_job_class_error(router) if namespace_name.empty? Object.const_get(namespace_name).const_get(:SweeperWorker) rescue NameError raise sweeper_job_class_error(router) end |
.internal_lib_path ⇒ Object
488 489 490 |
# File 'lib/ruby_reactor.rb', line 488 def self.internal_lib_path File.join(root.to_s, "lib") end |
.reactor_storage_name(reactor_class) ⇒ Object
420 421 422 423 424 |
# File 'lib/ruby_reactor.rb', line 420 def self.reactor_storage_name(reactor_class) return "AnonymousReactor" if reactor_class.nil? reactor_class.name || "AnonymousReactor" end |
.root ⇒ Object
484 485 486 |
# File 'lib/ruby_reactor.rb', line 484 def self.root Pathname.new(File.("..", __dir__)) end |
.Skipped ⇒ Object
Build a Skipped result. Return one from a step's run block to mark
that single step skipped while the reactor continues.
381 382 383 |
# File 'lib/ruby_reactor.rb', line 381 def self.Skipped(...) Skipped.new(...) end |
.start_sweeper! ⇒ Object
Kick the self-rescheduling recovery sweeper chain. Call once per cluster —
typically from an initializer (RubyReactor.start_sweeper!). Idempotent:
calling it on every process boot is safe because the worker claims each tick
by time-window, so duplicate kicks collapse to a single chain. No-op when
config.sweeper_enabled is false. Returns the scheduled job id, or nil when
disabled or when this window's tick was already claimed by another caller.
432 433 434 435 436 |
# File 'lib/ruby_reactor.rb', line 432 def self.start_sweeper! return unless configuration.sweeper_enabled sweeper_job_class.schedule_next end |
.Success(value = nil) ⇒ Object
Global helper methods
365 366 367 |
# File 'lib/ruby_reactor.rb', line 365 def self.Success(value = nil) Success.new(value) end |
.sweep_once(limit: nil) ⇒ Object
Run both recovery sweepers exactly once and return their counts. The
synchronous escape hatch for hosts that schedule recovery with their own
cron / k8s CronJob instead of the in-cluster chain (set
config.sweeper_enabled = false and call this from rake ruby_reactor:sweep
or a binstub).
475 476 477 478 479 480 481 482 |
# File 'lib/ruby_reactor.rb', line 475 def self.sweep_once(limit: nil) limit ||= configuration.sweeper_limit { reactors: Sweeper.run_once(limit: limit), maps: Map::Sweeper.run_once(limit: limit), async_steps: StepSweeper.run_once(limit: limit) } end |
.sweeper_job_class ⇒ Object
The sweeper job class living alongside the configured async_router
(e.g. Adapters::Sidekiq::Router -> Adapters::Sidekiq::SweeperWorker),
so the chain is kicked through whichever backend is configured instead of
a hardcoded Sidekiq class. Known built-in routers are mapped explicitly;
a custom configuration.async_router falls back to a sibling-namespace
lookup, with a clear error (instead of a bare NameError) when that
convention doesn't hold.
445 446 447 448 449 450 451 452 453 |
# File 'lib/ruby_reactor.rb', line 445 def self.sweeper_job_class router = configuration.async_router case router.name when "RubyReactor::Adapters::Sidekiq::Router" then Adapters::Sidekiq::SweeperWorker when "RubyReactor::Adapters::ActiveJob::Router" then Adapters::ActiveJob::SweeperWorker else inferred_sweeper_job_class(router) end end |
.sweeper_job_class_error(router) ⇒ Object
464 465 466 467 468 |
# File 'lib/ruby_reactor.rb', line 464 def self.sweeper_job_class_error(router) "RubyReactor: cannot infer a sweeper job class for custom async_router " \ "#{router.inspect}. Define a `SweeperWorker` class alongside it " \ "(same namespace), or override `RubyReactor.sweeper_job_class`." end |