ruby_reactor 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +98 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/README.md +570 -0
- data/Rakefile +12 -0
- data/documentation/DAG.md +457 -0
- data/documentation/README.md +123 -0
- data/documentation/async_reactors.md +369 -0
- data/documentation/composition.md +199 -0
- data/documentation/core_concepts.md +662 -0
- data/documentation/data_pipelines.md +224 -0
- data/documentation/examples/inventory_management.md +749 -0
- data/documentation/examples/order_processing.md +365 -0
- data/documentation/examples/payment_processing.md +654 -0
- data/documentation/getting_started.md +224 -0
- data/documentation/retry_configuration.md +357 -0
- data/lib/ruby_reactor/async_router.rb +91 -0
- data/lib/ruby_reactor/configuration.rb +41 -0
- data/lib/ruby_reactor/context.rb +169 -0
- data/lib/ruby_reactor/context_serializer.rb +164 -0
- data/lib/ruby_reactor/dependency_graph.rb +126 -0
- data/lib/ruby_reactor/dsl/compose_builder.rb +86 -0
- data/lib/ruby_reactor/dsl/map_builder.rb +112 -0
- data/lib/ruby_reactor/dsl/reactor.rb +151 -0
- data/lib/ruby_reactor/dsl/step_builder.rb +177 -0
- data/lib/ruby_reactor/dsl/template_helpers.rb +36 -0
- data/lib/ruby_reactor/dsl/validation_helpers.rb +35 -0
- data/lib/ruby_reactor/error/base.rb +16 -0
- data/lib/ruby_reactor/error/compensation_error.rb +8 -0
- data/lib/ruby_reactor/error/context_too_large_error.rb +11 -0
- data/lib/ruby_reactor/error/dependency_error.rb +8 -0
- data/lib/ruby_reactor/error/deserialization_error.rb +11 -0
- data/lib/ruby_reactor/error/input_validation_error.rb +29 -0
- data/lib/ruby_reactor/error/schema_version_error.rb +11 -0
- data/lib/ruby_reactor/error/step_failure_error.rb +18 -0
- data/lib/ruby_reactor/error/undo_error.rb +8 -0
- data/lib/ruby_reactor/error/validation_error.rb +8 -0
- data/lib/ruby_reactor/executor/compensation_manager.rb +79 -0
- data/lib/ruby_reactor/executor/graph_manager.rb +41 -0
- data/lib/ruby_reactor/executor/input_validator.rb +39 -0
- data/lib/ruby_reactor/executor/result_handler.rb +103 -0
- data/lib/ruby_reactor/executor/retry_manager.rb +156 -0
- data/lib/ruby_reactor/executor/step_executor.rb +319 -0
- data/lib/ruby_reactor/executor.rb +123 -0
- data/lib/ruby_reactor/map/collector.rb +65 -0
- data/lib/ruby_reactor/map/element_executor.rb +154 -0
- data/lib/ruby_reactor/map/execution.rb +60 -0
- data/lib/ruby_reactor/map/helpers.rb +67 -0
- data/lib/ruby_reactor/max_retries_exhausted_failure.rb +19 -0
- data/lib/ruby_reactor/reactor.rb +75 -0
- data/lib/ruby_reactor/retry_context.rb +92 -0
- data/lib/ruby_reactor/retry_queued_result.rb +26 -0
- data/lib/ruby_reactor/sidekiq_workers/map_collector_worker.rb +13 -0
- data/lib/ruby_reactor/sidekiq_workers/map_element_worker.rb +13 -0
- data/lib/ruby_reactor/sidekiq_workers/map_execution_worker.rb +15 -0
- data/lib/ruby_reactor/sidekiq_workers/worker.rb +55 -0
- data/lib/ruby_reactor/step/compose_step.rb +107 -0
- data/lib/ruby_reactor/step/map_step.rb +234 -0
- data/lib/ruby_reactor/step.rb +33 -0
- data/lib/ruby_reactor/storage/adapter.rb +51 -0
- data/lib/ruby_reactor/storage/configuration.rb +15 -0
- data/lib/ruby_reactor/storage/redis_adapter.rb +140 -0
- data/lib/ruby_reactor/template/base.rb +15 -0
- data/lib/ruby_reactor/template/element.rb +25 -0
- data/lib/ruby_reactor/template/input.rb +48 -0
- data/lib/ruby_reactor/template/result.rb +48 -0
- data/lib/ruby_reactor/template/value.rb +22 -0
- data/lib/ruby_reactor/validation/base.rb +26 -0
- data/lib/ruby_reactor/validation/input_validator.rb +62 -0
- data/lib/ruby_reactor/validation/schema_builder.rb +17 -0
- data/lib/ruby_reactor/version.rb +5 -0
- data/lib/ruby_reactor.rb +159 -0
- data/sig/ruby_reactor.rbs +4 -0
- metadata +178 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyReactor
|
|
4
|
+
module Template
|
|
5
|
+
class Element < Base
|
|
6
|
+
attr_reader :map_name, :path
|
|
7
|
+
|
|
8
|
+
def initialize(map_name, path = nil)
|
|
9
|
+
super()
|
|
10
|
+
@map_name = map_name
|
|
11
|
+
@path = path
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def resolve(_context)
|
|
15
|
+
# Element resolution happens inside MapStep, not generic resolve
|
|
16
|
+
# But if called in wrong context, raise error
|
|
17
|
+
raise RubyReactor::Error::DependencyError, "element() can only be used within a map argument mapping"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def inspect
|
|
21
|
+
"element(:#{@map_name}#{", #{@path.inspect}" if @path})"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyReactor
|
|
4
|
+
module Template
|
|
5
|
+
class Input < Base
|
|
6
|
+
attr_reader :name, :path
|
|
7
|
+
|
|
8
|
+
def initialize(name, path = nil)
|
|
9
|
+
super()
|
|
10
|
+
@name = name
|
|
11
|
+
@path = path
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def resolve(context)
|
|
15
|
+
value = context.get_input(@name)
|
|
16
|
+
return nil if value.nil?
|
|
17
|
+
|
|
18
|
+
if @path
|
|
19
|
+
extract_path(value, @path)
|
|
20
|
+
else
|
|
21
|
+
value
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def inspect
|
|
26
|
+
if @path
|
|
27
|
+
"input(:#{@name}, #{@path.inspect})"
|
|
28
|
+
else
|
|
29
|
+
"input(:#{@name})"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def extract_path(value, path)
|
|
36
|
+
if path.is_a?(Symbol) && value.respond_to?(:[])
|
|
37
|
+
value[path]
|
|
38
|
+
elsif path.is_a?(String)
|
|
39
|
+
path.split(".").reduce(value) { |v, key| v&.send(:[], key) }
|
|
40
|
+
elsif path.is_a?(Array)
|
|
41
|
+
path.reduce(value) { |v, key| v&.send(:[], key) }
|
|
42
|
+
elsif value.respond_to?(path)
|
|
43
|
+
value.send(path)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyReactor
|
|
4
|
+
module Template
|
|
5
|
+
class Result < Base
|
|
6
|
+
attr_reader :step_name, :path
|
|
7
|
+
|
|
8
|
+
def initialize(step_name, path = nil)
|
|
9
|
+
super()
|
|
10
|
+
@step_name = step_name
|
|
11
|
+
@path = path
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def resolve(context)
|
|
15
|
+
value = context.get_result(@step_name)
|
|
16
|
+
return nil if value.nil?
|
|
17
|
+
|
|
18
|
+
if @path
|
|
19
|
+
extract_path(value, @path)
|
|
20
|
+
else
|
|
21
|
+
value
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def inspect
|
|
26
|
+
if @path
|
|
27
|
+
"result(:#{@step_name}, #{@path.inspect})"
|
|
28
|
+
else
|
|
29
|
+
"result(:#{@step_name})"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def extract_path(value, path)
|
|
36
|
+
if path.is_a?(Symbol) && value.respond_to?(:[])
|
|
37
|
+
value[path]
|
|
38
|
+
elsif path.is_a?(String)
|
|
39
|
+
path.split(".").reduce(value) { |v, key| v&.send(:[], key) }
|
|
40
|
+
elsif path.is_a?(Array)
|
|
41
|
+
path.reduce(value) { |v, key| v&.send(:[], key) }
|
|
42
|
+
elsif value.respond_to?(path)
|
|
43
|
+
value.send(path)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyReactor
|
|
4
|
+
module Template
|
|
5
|
+
class Value < Base
|
|
6
|
+
attr_reader :value
|
|
7
|
+
|
|
8
|
+
def initialize(value)
|
|
9
|
+
super()
|
|
10
|
+
@value = value
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def resolve(_context)
|
|
14
|
+
@value
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def inspect
|
|
18
|
+
"value(#{@value.inspect})"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyReactor
|
|
4
|
+
module Validation
|
|
5
|
+
class Base
|
|
6
|
+
def self.call(data)
|
|
7
|
+
new.call(data)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def call(data)
|
|
11
|
+
raise NotImplementedError
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
protected
|
|
15
|
+
|
|
16
|
+
def success(value)
|
|
17
|
+
RubyReactor.Success(value)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def failure(errors)
|
|
21
|
+
error = RubyReactor::Error::InputValidationError.new(errors)
|
|
22
|
+
RubyReactor.Failure(error)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dry-validation"
|
|
4
|
+
|
|
5
|
+
module RubyReactor
|
|
6
|
+
module Validation
|
|
7
|
+
class InputValidator < Base
|
|
8
|
+
attr_reader :schema
|
|
9
|
+
|
|
10
|
+
def initialize(schema)
|
|
11
|
+
super()
|
|
12
|
+
@schema = schema
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def call(data)
|
|
16
|
+
result = schema.call(data)
|
|
17
|
+
|
|
18
|
+
if result.success?
|
|
19
|
+
success(result.to_h)
|
|
20
|
+
else
|
|
21
|
+
failure(format_errors(result.errors))
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def format_errors(errors)
|
|
28
|
+
formatted = {}
|
|
29
|
+
flatten_errors(errors.to_h, formatted, [])
|
|
30
|
+
formatted
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def flatten_errors(errors_hash, formatted, path)
|
|
34
|
+
errors_hash.each do |key, messages|
|
|
35
|
+
current_path = path + [key]
|
|
36
|
+
|
|
37
|
+
case messages
|
|
38
|
+
when Array
|
|
39
|
+
# This is a leaf node with error messages
|
|
40
|
+
flat_key = if current_path.size == 1
|
|
41
|
+
current_path.first.to_s
|
|
42
|
+
else
|
|
43
|
+
"#{current_path.first}#{current_path[1..].map { |k| "[#{k}]" }.join}"
|
|
44
|
+
end
|
|
45
|
+
formatted[flat_key.to_sym] = messages.join(", ")
|
|
46
|
+
when Hash
|
|
47
|
+
# This is a nested structure, recurse
|
|
48
|
+
flatten_errors(messages, formatted, current_path)
|
|
49
|
+
else
|
|
50
|
+
# Single message
|
|
51
|
+
flat_key = if current_path.size == 1
|
|
52
|
+
current_path.first.to_s
|
|
53
|
+
else
|
|
54
|
+
"#{current_path.first}#{current_path[1..].map { |k| "[#{k}]" }.join}"
|
|
55
|
+
end
|
|
56
|
+
formatted[flat_key.to_sym] = messages.to_s
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dry-validation"
|
|
4
|
+
|
|
5
|
+
module RubyReactor
|
|
6
|
+
module Validation
|
|
7
|
+
class SchemaBuilder
|
|
8
|
+
def self.build_from_block(&block)
|
|
9
|
+
Dry::Schema.Params(&block)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.build_contract_from_block(&block)
|
|
13
|
+
Class.new(Dry::Validation::Contract, &block).new
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
data/lib/ruby_reactor.rb
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "zeitwerk"
|
|
4
|
+
|
|
5
|
+
# Load dry-validation if available (for validation features)
|
|
6
|
+
begin
|
|
7
|
+
require "dry-validation"
|
|
8
|
+
rescue LoadError
|
|
9
|
+
# dry-validation is optional, validation features won't be available
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Load sidekiq if available (for async features)
|
|
13
|
+
begin
|
|
14
|
+
require "sidekiq"
|
|
15
|
+
rescue LoadError
|
|
16
|
+
# sidekiq is optional, async features won't be available
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
loader = Zeitwerk::Loader.for_gem
|
|
20
|
+
loader.setup
|
|
21
|
+
|
|
22
|
+
module RubyReactor
|
|
23
|
+
# Success/Failure pattern for results
|
|
24
|
+
class Success
|
|
25
|
+
attr_reader :value
|
|
26
|
+
|
|
27
|
+
def initialize(value = nil)
|
|
28
|
+
@value = value
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def success?
|
|
32
|
+
true
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def failure?
|
|
36
|
+
false
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class Failure
|
|
41
|
+
attr_reader :error, :retryable, :step_name, :inputs, :backtrace, :reactor_name, :step_arguments
|
|
42
|
+
|
|
43
|
+
# rubocop:disable Metrics/ParameterLists
|
|
44
|
+
def initialize(error, retryable: nil, step_name: nil, inputs: {}, backtrace: nil, redact_inputs: [],
|
|
45
|
+
reactor_name: nil, step_arguments: {})
|
|
46
|
+
# rubocop:enable Metrics/ParameterLists
|
|
47
|
+
@error = error
|
|
48
|
+
@retryable = if retryable.nil?
|
|
49
|
+
error.respond_to?(:retryable?) ? error.retryable? : true
|
|
50
|
+
else
|
|
51
|
+
retryable
|
|
52
|
+
end
|
|
53
|
+
@step_name = step_name
|
|
54
|
+
@reactor_name = reactor_name
|
|
55
|
+
@inputs = inputs
|
|
56
|
+
@step_arguments = step_arguments
|
|
57
|
+
@backtrace = backtrace || (error.respond_to?(:backtrace) ? error.backtrace : caller)
|
|
58
|
+
@redact_inputs = redact_inputs
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def success?
|
|
62
|
+
false
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def failure?
|
|
66
|
+
true
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def retryable?
|
|
70
|
+
@retryable
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def message
|
|
74
|
+
msg = []
|
|
75
|
+
header = "Error"
|
|
76
|
+
header += " in reactor '#{reactor_name}'" if reactor_name
|
|
77
|
+
header += " step '#{step_name}'" if step_name
|
|
78
|
+
header += ": #{error_message}"
|
|
79
|
+
|
|
80
|
+
msg << header
|
|
81
|
+
|
|
82
|
+
if inputs && !inputs.empty?
|
|
83
|
+
msg << "Inputs:"
|
|
84
|
+
inputs.each do |key, value|
|
|
85
|
+
val = @redact_inputs.include?(key) ? "[REDACTED]" : value.inspect
|
|
86
|
+
msg << " #{key}: #{val}"
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
if step_arguments && !step_arguments.empty?
|
|
91
|
+
msg << "Step Arguments:"
|
|
92
|
+
step_arguments.each do |key, value|
|
|
93
|
+
# We might want to redact step arguments too if they come from redacted inputs
|
|
94
|
+
# For now, let's assume if the input key matches a redacted input key, it should be redacted
|
|
95
|
+
# But step arguments have different names.
|
|
96
|
+
# We can't easily track redaction for step arguments without more metadata.
|
|
97
|
+
# For now, let's just display them.
|
|
98
|
+
msg << " #{key}: #{value.inspect}"
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
if backtrace
|
|
103
|
+
msg << "Backtrace:"
|
|
104
|
+
msg << backtrace.take(5).map { |line| " #{line}" }.join("\n")
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
msg.join("\n")
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def to_s
|
|
111
|
+
message
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
private
|
|
115
|
+
|
|
116
|
+
def error_message
|
|
117
|
+
@error.respond_to?(:message) ? @error.message : @error.to_s
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Async result for background job execution
|
|
122
|
+
class AsyncResult
|
|
123
|
+
attr_reader :job_id, :intermediate_results
|
|
124
|
+
|
|
125
|
+
def initialize(job_id:, intermediate_results: {})
|
|
126
|
+
@job_id = job_id
|
|
127
|
+
@intermediate_results = intermediate_results
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def async?
|
|
131
|
+
true
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def success?
|
|
135
|
+
false
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def failure?
|
|
139
|
+
false
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Global helper methods
|
|
144
|
+
def self.Success(value = nil)
|
|
145
|
+
Success.new(value)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def self.Failure(error, **kwargs)
|
|
149
|
+
Failure.new(error, **kwargs)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def self.configure
|
|
153
|
+
yield(Configuration.instance) if block_given?
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def self.configuration
|
|
157
|
+
Configuration.instance
|
|
158
|
+
end
|
|
159
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: ruby_reactor
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Artur
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2025-12-02 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: dry-validation
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.10'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '1.10'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: redis
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '5.0'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '5.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: sidekiq
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '7.0'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '7.0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: zeitwerk
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '2.6'
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '2.6'
|
|
69
|
+
description: Ruby Reactor implements the Saga pattern with compensation-based error
|
|
70
|
+
handling and DAG-based execution planning. It supports async execution via Sidekiq
|
|
71
|
+
and persistence via Redis.
|
|
72
|
+
email:
|
|
73
|
+
- 1930175+arturictus@users.noreply.github.com
|
|
74
|
+
executables: []
|
|
75
|
+
extensions: []
|
|
76
|
+
extra_rdoc_files: []
|
|
77
|
+
files:
|
|
78
|
+
- ".rspec"
|
|
79
|
+
- ".rubocop.yml"
|
|
80
|
+
- CODE_OF_CONDUCT.md
|
|
81
|
+
- README.md
|
|
82
|
+
- Rakefile
|
|
83
|
+
- documentation/DAG.md
|
|
84
|
+
- documentation/README.md
|
|
85
|
+
- documentation/async_reactors.md
|
|
86
|
+
- documentation/composition.md
|
|
87
|
+
- documentation/core_concepts.md
|
|
88
|
+
- documentation/data_pipelines.md
|
|
89
|
+
- documentation/examples/inventory_management.md
|
|
90
|
+
- documentation/examples/order_processing.md
|
|
91
|
+
- documentation/examples/payment_processing.md
|
|
92
|
+
- documentation/getting_started.md
|
|
93
|
+
- documentation/retry_configuration.md
|
|
94
|
+
- lib/ruby_reactor.rb
|
|
95
|
+
- lib/ruby_reactor/async_router.rb
|
|
96
|
+
- lib/ruby_reactor/configuration.rb
|
|
97
|
+
- lib/ruby_reactor/context.rb
|
|
98
|
+
- lib/ruby_reactor/context_serializer.rb
|
|
99
|
+
- lib/ruby_reactor/dependency_graph.rb
|
|
100
|
+
- lib/ruby_reactor/dsl/compose_builder.rb
|
|
101
|
+
- lib/ruby_reactor/dsl/map_builder.rb
|
|
102
|
+
- lib/ruby_reactor/dsl/reactor.rb
|
|
103
|
+
- lib/ruby_reactor/dsl/step_builder.rb
|
|
104
|
+
- lib/ruby_reactor/dsl/template_helpers.rb
|
|
105
|
+
- lib/ruby_reactor/dsl/validation_helpers.rb
|
|
106
|
+
- lib/ruby_reactor/error/base.rb
|
|
107
|
+
- lib/ruby_reactor/error/compensation_error.rb
|
|
108
|
+
- lib/ruby_reactor/error/context_too_large_error.rb
|
|
109
|
+
- lib/ruby_reactor/error/dependency_error.rb
|
|
110
|
+
- lib/ruby_reactor/error/deserialization_error.rb
|
|
111
|
+
- lib/ruby_reactor/error/input_validation_error.rb
|
|
112
|
+
- lib/ruby_reactor/error/schema_version_error.rb
|
|
113
|
+
- lib/ruby_reactor/error/step_failure_error.rb
|
|
114
|
+
- lib/ruby_reactor/error/undo_error.rb
|
|
115
|
+
- lib/ruby_reactor/error/validation_error.rb
|
|
116
|
+
- lib/ruby_reactor/executor.rb
|
|
117
|
+
- lib/ruby_reactor/executor/compensation_manager.rb
|
|
118
|
+
- lib/ruby_reactor/executor/graph_manager.rb
|
|
119
|
+
- lib/ruby_reactor/executor/input_validator.rb
|
|
120
|
+
- lib/ruby_reactor/executor/result_handler.rb
|
|
121
|
+
- lib/ruby_reactor/executor/retry_manager.rb
|
|
122
|
+
- lib/ruby_reactor/executor/step_executor.rb
|
|
123
|
+
- lib/ruby_reactor/map/collector.rb
|
|
124
|
+
- lib/ruby_reactor/map/element_executor.rb
|
|
125
|
+
- lib/ruby_reactor/map/execution.rb
|
|
126
|
+
- lib/ruby_reactor/map/helpers.rb
|
|
127
|
+
- lib/ruby_reactor/max_retries_exhausted_failure.rb
|
|
128
|
+
- lib/ruby_reactor/reactor.rb
|
|
129
|
+
- lib/ruby_reactor/retry_context.rb
|
|
130
|
+
- lib/ruby_reactor/retry_queued_result.rb
|
|
131
|
+
- lib/ruby_reactor/sidekiq_workers/map_collector_worker.rb
|
|
132
|
+
- lib/ruby_reactor/sidekiq_workers/map_element_worker.rb
|
|
133
|
+
- lib/ruby_reactor/sidekiq_workers/map_execution_worker.rb
|
|
134
|
+
- lib/ruby_reactor/sidekiq_workers/worker.rb
|
|
135
|
+
- lib/ruby_reactor/step.rb
|
|
136
|
+
- lib/ruby_reactor/step/compose_step.rb
|
|
137
|
+
- lib/ruby_reactor/step/map_step.rb
|
|
138
|
+
- lib/ruby_reactor/storage/adapter.rb
|
|
139
|
+
- lib/ruby_reactor/storage/configuration.rb
|
|
140
|
+
- lib/ruby_reactor/storage/redis_adapter.rb
|
|
141
|
+
- lib/ruby_reactor/template/base.rb
|
|
142
|
+
- lib/ruby_reactor/template/element.rb
|
|
143
|
+
- lib/ruby_reactor/template/input.rb
|
|
144
|
+
- lib/ruby_reactor/template/result.rb
|
|
145
|
+
- lib/ruby_reactor/template/value.rb
|
|
146
|
+
- lib/ruby_reactor/validation/base.rb
|
|
147
|
+
- lib/ruby_reactor/validation/input_validator.rb
|
|
148
|
+
- lib/ruby_reactor/validation/schema_builder.rb
|
|
149
|
+
- lib/ruby_reactor/version.rb
|
|
150
|
+
- sig/ruby_reactor.rbs
|
|
151
|
+
homepage: https://github.com/arturictus/ruby_reactor
|
|
152
|
+
licenses: []
|
|
153
|
+
metadata:
|
|
154
|
+
allowed_push_host: https://rubygems.org
|
|
155
|
+
rubygems_mfa_required: 'true'
|
|
156
|
+
homepage_uri: https://github.com/arturictus/ruby_reactor
|
|
157
|
+
source_code_uri: https://github.com/arturictus/ruby_reactor
|
|
158
|
+
changelog_uri: https://github.com/arturictus/ruby_reactor/blob/main/CHANGELOG.md
|
|
159
|
+
post_install_message:
|
|
160
|
+
rdoc_options: []
|
|
161
|
+
require_paths:
|
|
162
|
+
- lib
|
|
163
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
164
|
+
requirements:
|
|
165
|
+
- - ">="
|
|
166
|
+
- !ruby/object:Gem::Version
|
|
167
|
+
version: 3.0.0
|
|
168
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
169
|
+
requirements:
|
|
170
|
+
- - ">="
|
|
171
|
+
- !ruby/object:Gem::Version
|
|
172
|
+
version: '0'
|
|
173
|
+
requirements: []
|
|
174
|
+
rubygems_version: 3.4.19
|
|
175
|
+
signing_key:
|
|
176
|
+
specification_version: 4
|
|
177
|
+
summary: A dynamic, concurrent, dependency-resolving saga orchestrator for Ruby.
|
|
178
|
+
test_files: []
|