ruby_reactor 0.4.0 → 0.5.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 +4 -4
- data/.release-please-config.json +3 -0
- data/.release-please-manifest.json +1 -1
- data/.rubocop.yml +1 -0
- data/CHANGELOG.md +15 -0
- data/README.md +8 -2
- data/lib/ruby_reactor/configuration.rb +6 -1
- data/lib/ruby_reactor/context.rb +6 -2
- data/lib/ruby_reactor/context_serializer.rb +44 -2
- data/lib/ruby_reactor/dsl/reactor.rb +16 -3
- data/lib/ruby_reactor/executor/compensation_manager.rb +75 -47
- data/lib/ruby_reactor/executor/result_handler.rb +1 -12
- data/lib/ruby_reactor/executor/retry_manager.rb +15 -5
- data/lib/ruby_reactor/executor/step_executor.rb +36 -18
- data/lib/ruby_reactor/executor.rb +119 -37
- data/lib/ruby_reactor/map/collector.rb +4 -4
- data/lib/ruby_reactor/map/element_executor.rb +15 -1
- data/lib/ruby_reactor/map/helpers.rb +17 -4
- data/lib/ruby_reactor/middleware.rb +13 -0
- data/lib/ruby_reactor/middleware_runner.rb +29 -0
- data/lib/ruby_reactor/open_telemetry.rb +647 -0
- data/lib/ruby_reactor/reactor.rb +12 -4
- data/lib/ruby_reactor/rspec/test_subject.rb +0 -1
- data/lib/ruby_reactor/sidekiq_adapter.rb +7 -21
- data/lib/ruby_reactor/step/map_step.rb +25 -33
- data/lib/ruby_reactor/storage/redis_adapter.rb +10 -3
- data/lib/ruby_reactor/storage/redis_locking.rb +17 -0
- data/lib/ruby_reactor/utils/backtrace_location.rb +37 -0
- data/lib/ruby_reactor/version.rb +1 -1
- data/lib/ruby_reactor/web/api.rb +68 -8
- data/lib/ruby_reactor/web/coordination_serializer.rb +174 -0
- data/lib/ruby_reactor/web/public/assets/index-CCnNVQy5.css +1 -0
- data/lib/ruby_reactor/web/public/assets/index-D7IBZvos.js +21 -0
- data/lib/ruby_reactor/web/public/index.html +2 -2
- data/lib/ruby_reactor.rb +7 -2
- data/teley/Dockerfile +60 -0
- metadata +10 -6
- data/lib/ruby_reactor/map/execution.rb +0 -101
- data/lib/ruby_reactor/sidekiq_workers/map_execution_worker.rb +0 -15
- data/lib/ruby_reactor/web/public/assets/index-VdeLgH9k.js +0 -19
- data/lib/ruby_reactor/web/public/assets/index-_z-6BvuM.css +0 -1
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<link rel="icon" type="image/svg+xml" href="./vite.svg" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>ui</title>
|
|
8
|
-
<script type="module" crossorigin src="./assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
8
|
+
<script type="module" crossorigin src="./assets/index-D7IBZvos.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="./assets/index-CCnNVQy5.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|
data/lib/ruby_reactor.rb
CHANGED
|
@@ -238,13 +238,14 @@ module RubyReactor
|
|
|
238
238
|
return backtrace if ENV["RUBY_REACTOR_DEBUG"] == "true"
|
|
239
239
|
return backtrace if backtrace.nil? || backtrace.empty?
|
|
240
240
|
|
|
241
|
-
|
|
241
|
+
internal_prefix = RubyReactor.internal_lib_path
|
|
242
242
|
filtered = []
|
|
243
243
|
filtered << backtrace.first
|
|
244
244
|
|
|
245
245
|
internal_block = false
|
|
246
246
|
backtrace[1..]&.each do |line|
|
|
247
|
-
|
|
247
|
+
file_path, = RubyReactor::Utils::BacktraceLocation.parse(line)
|
|
248
|
+
if file_path&.start_with?(internal_prefix)
|
|
248
249
|
unless internal_block
|
|
249
250
|
filtered << "... [ruby-reactor-internals-redacted-trace]"
|
|
250
251
|
internal_block = true
|
|
@@ -331,4 +332,8 @@ module RubyReactor
|
|
|
331
332
|
def self.root
|
|
332
333
|
Pathname.new(File.expand_path("..", __dir__))
|
|
333
334
|
end
|
|
335
|
+
|
|
336
|
+
def self.internal_lib_path
|
|
337
|
+
File.join(root.to_s, "lib")
|
|
338
|
+
end
|
|
334
339
|
end
|
data/teley/Dockerfile
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Dockerfile for teley
|
|
2
|
+
FROM node:24-slim
|
|
3
|
+
|
|
4
|
+
WORKDIR /app
|
|
5
|
+
|
|
6
|
+
# Install git and other build deps
|
|
7
|
+
RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*
|
|
8
|
+
|
|
9
|
+
# Clone teley repo
|
|
10
|
+
RUN git clone https://github.com/logaretm/teley.git .
|
|
11
|
+
|
|
12
|
+
# Allow native builds for dependencies (like esbuild) via workspace config
|
|
13
|
+
RUN echo "dangerouslyAllowAllBuilds: true" > pnpm-workspace.yaml
|
|
14
|
+
|
|
15
|
+
# Patch workers/src/durable-object.ts to support default_token
|
|
16
|
+
RUN node -e ' \
|
|
17
|
+
const fs = require("fs"); \
|
|
18
|
+
const file = "workers/src/durable-object.ts"; \
|
|
19
|
+
let content = fs.readFileSync(file, "utf8"); \
|
|
20
|
+
content = content.replace("const token = url.searchParams.get(\x27token\x27);", "const token = url.searchParams.get(\x27token\x27) || \x27default_token\x27;"); \
|
|
21
|
+
fs.writeFileSync(file, content, "utf8"); \
|
|
22
|
+
'
|
|
23
|
+
|
|
24
|
+
# Patch app/pages/live/[roomId].vue to support default_token fallback
|
|
25
|
+
RUN node -e ' \
|
|
26
|
+
const fs = require("fs"); \
|
|
27
|
+
const file = "app/pages/live/[roomId].vue"; \
|
|
28
|
+
let content = fs.readFileSync(file, "utf8"); \
|
|
29
|
+
content = content.replace("const token = (route.query.token as string) || \x27\x27;", "const token = (route.query.token as string) || \x27default_token\x27;"); \
|
|
30
|
+
fs.writeFileSync(file, content, "utf8"); \
|
|
31
|
+
'
|
|
32
|
+
|
|
33
|
+
# Patch app/composables/useSession.ts to default to ruby_reactor_session and default_token
|
|
34
|
+
RUN node -e ' \
|
|
35
|
+
const fs = require("fs"); \
|
|
36
|
+
const file = "app/composables/useSession.ts"; \
|
|
37
|
+
let content = fs.readFileSync(file, "utf8"); \
|
|
38
|
+
content = content.replace(/const initialize = async \(\): Promise<void> => {[\s\S]*?};/, "const initialize = async (): Promise<void> => {\n if (initialized.value) return;\n roomId.value = \x27ruby_reactor_session\x27;\n receiveToken.value = \x27default_token\x27;\n isNewSession.value = false;\n initialized.value = true;\n };"); \
|
|
39
|
+
fs.writeFileSync(file, content, "utf8"); \
|
|
40
|
+
'
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# Enable corepack and install pnpm
|
|
44
|
+
RUN corepack enable && corepack prepare pnpm@latest --activate
|
|
45
|
+
|
|
46
|
+
# Install dependencies
|
|
47
|
+
RUN pnpm install --frozen-lockfile
|
|
48
|
+
|
|
49
|
+
# Build the Nuxt static files
|
|
50
|
+
RUN pnpm build
|
|
51
|
+
|
|
52
|
+
# Expose port
|
|
53
|
+
EXPOSE 3000
|
|
54
|
+
|
|
55
|
+
ENV HOST=0.0.0.0
|
|
56
|
+
ENV PORT=3000
|
|
57
|
+
|
|
58
|
+
# Start Cloudflare Pages local dev server via wrangler
|
|
59
|
+
WORKDIR /app/workers
|
|
60
|
+
CMD ["npx", "wrangler", "dev", "--ip", "0.0.0.0", "--port", "3000"]
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruby_reactor
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Artur
|
|
@@ -133,10 +133,12 @@ files:
|
|
|
133
133
|
- lib/ruby_reactor/map/collector.rb
|
|
134
134
|
- lib/ruby_reactor/map/dispatcher.rb
|
|
135
135
|
- lib/ruby_reactor/map/element_executor.rb
|
|
136
|
-
- lib/ruby_reactor/map/execution.rb
|
|
137
136
|
- lib/ruby_reactor/map/helpers.rb
|
|
138
137
|
- lib/ruby_reactor/map/result_enumerator.rb
|
|
139
138
|
- lib/ruby_reactor/max_retries_exhausted_failure.rb
|
|
139
|
+
- lib/ruby_reactor/middleware.rb
|
|
140
|
+
- lib/ruby_reactor/middleware_runner.rb
|
|
141
|
+
- lib/ruby_reactor/open_telemetry.rb
|
|
140
142
|
- lib/ruby_reactor/period.rb
|
|
141
143
|
- lib/ruby_reactor/rate_limit.rb
|
|
142
144
|
- lib/ruby_reactor/reactor.rb
|
|
@@ -152,7 +154,6 @@ files:
|
|
|
152
154
|
- lib/ruby_reactor/sidekiq_adapter.rb
|
|
153
155
|
- lib/ruby_reactor/sidekiq_workers/map_collector_worker.rb
|
|
154
156
|
- lib/ruby_reactor/sidekiq_workers/map_element_worker.rb
|
|
155
|
-
- lib/ruby_reactor/sidekiq_workers/map_execution_worker.rb
|
|
156
157
|
- lib/ruby_reactor/sidekiq_workers/worker.rb
|
|
157
158
|
- lib/ruby_reactor/step.rb
|
|
158
159
|
- lib/ruby_reactor/step/compose_step.rb
|
|
@@ -167,6 +168,7 @@ files:
|
|
|
167
168
|
- lib/ruby_reactor/template/input.rb
|
|
168
169
|
- lib/ruby_reactor/template/result.rb
|
|
169
170
|
- lib/ruby_reactor/template/value.rb
|
|
171
|
+
- lib/ruby_reactor/utils/backtrace_location.rb
|
|
170
172
|
- lib/ruby_reactor/utils/code_extractor.rb
|
|
171
173
|
- lib/ruby_reactor/validation/base.rb
|
|
172
174
|
- lib/ruby_reactor/validation/input_validator.rb
|
|
@@ -175,13 +177,15 @@ files:
|
|
|
175
177
|
- lib/ruby_reactor/web/api.rb
|
|
176
178
|
- lib/ruby_reactor/web/application.rb
|
|
177
179
|
- lib/ruby_reactor/web/config.ru
|
|
178
|
-
- lib/ruby_reactor/web/
|
|
179
|
-
- lib/ruby_reactor/web/public/assets/index-
|
|
180
|
+
- lib/ruby_reactor/web/coordination_serializer.rb
|
|
181
|
+
- lib/ruby_reactor/web/public/assets/index-CCnNVQy5.css
|
|
182
|
+
- lib/ruby_reactor/web/public/assets/index-D7IBZvos.js
|
|
180
183
|
- lib/ruby_reactor/web/public/index.html
|
|
181
184
|
- lib/ruby_reactor/web/public/vite.svg
|
|
182
185
|
- llms-full.txt
|
|
183
186
|
- llms.txt
|
|
184
187
|
- sig/ruby_reactor.rbs
|
|
188
|
+
- teley/Dockerfile
|
|
185
189
|
homepage: https://github.com/arturictus/ruby_reactor
|
|
186
190
|
licenses: []
|
|
187
191
|
metadata:
|
|
@@ -204,7 +208,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
204
208
|
- !ruby/object:Gem::Version
|
|
205
209
|
version: '0'
|
|
206
210
|
requirements: []
|
|
207
|
-
rubygems_version:
|
|
211
|
+
rubygems_version: 3.6.9
|
|
208
212
|
specification_version: 4
|
|
209
213
|
summary: A dynamic, concurrent, dependency-resolving saga orchestrator for Ruby.
|
|
210
214
|
test_files: []
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module RubyReactor
|
|
4
|
-
module Map
|
|
5
|
-
class Execution
|
|
6
|
-
extend Helpers
|
|
7
|
-
|
|
8
|
-
def self.perform(arguments)
|
|
9
|
-
arguments = arguments.transform_keys(&:to_sym)
|
|
10
|
-
storage = RubyReactor.configuration.storage_adapter
|
|
11
|
-
|
|
12
|
-
parent_context = load_parent_context_from_storage(
|
|
13
|
-
arguments[:parent_context_id], arguments[:parent_reactor_class_name], storage
|
|
14
|
-
)
|
|
15
|
-
reactor_class = resolve_reactor_class(arguments[:reactor_class_info])
|
|
16
|
-
inputs = ContextSerializer.deserialize_value(arguments[:serialized_inputs])
|
|
17
|
-
|
|
18
|
-
results = execute_all_elements(
|
|
19
|
-
source: inputs[:source], mappings: inputs[:mappings],
|
|
20
|
-
reactor_class: reactor_class, parent_context: parent_context,
|
|
21
|
-
storage_options: {
|
|
22
|
-
map_id: arguments[:map_id], storage: storage,
|
|
23
|
-
parent_reactor_class_name: arguments[:parent_reactor_class_name],
|
|
24
|
-
strict_ordering: arguments[:strict_ordering],
|
|
25
|
-
fail_fast: arguments[:fail_fast]
|
|
26
|
-
}
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
finalize_execution(results, parent_context, arguments[:step_name], arguments[:parent_reactor_class_name],
|
|
30
|
-
storage)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def self.execute_all_elements(source:, mappings:, reactor_class:, parent_context:, storage_options:)
|
|
34
|
-
# rubocop:disable Metrics/BlockLength
|
|
35
|
-
source.map.with_index do |element, index|
|
|
36
|
-
if storage_options[:fail_fast]
|
|
37
|
-
failed_context_id = storage_options[:storage].retrieve_map_failed_context_id(
|
|
38
|
-
storage_options[:map_id], storage_options[:parent_reactor_class_name]
|
|
39
|
-
)
|
|
40
|
-
next if failed_context_id
|
|
41
|
-
end
|
|
42
|
-
element_inputs = build_element_inputs(mappings, parent_context, element)
|
|
43
|
-
|
|
44
|
-
# Manually create and link context to ensure parent_context_id is set
|
|
45
|
-
child_context = RubyReactor::Context.new(element_inputs, reactor_class)
|
|
46
|
-
link_contexts(child_context, parent_context)
|
|
47
|
-
|
|
48
|
-
# Ensure we store the element context linkage
|
|
49
|
-
storage_options[:storage].store_map_element_context_id(
|
|
50
|
-
storage_options[:map_id], child_context.context_id, storage_options[:parent_reactor_class_name]
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
# Set map metadata for failure handling
|
|
54
|
-
metadata = {
|
|
55
|
-
map_id: storage_options[:map_id],
|
|
56
|
-
parent_reactor_class_name: storage_options[:parent_reactor_class_name],
|
|
57
|
-
index: index
|
|
58
|
-
}
|
|
59
|
-
child_context.map_metadata = metadata
|
|
60
|
-
|
|
61
|
-
executor = RubyReactor::Executor.new(reactor_class, {}, child_context)
|
|
62
|
-
executor.execute
|
|
63
|
-
result = executor.result
|
|
64
|
-
|
|
65
|
-
store_result(result, index, storage_options)
|
|
66
|
-
|
|
67
|
-
if result.failure? && storage_options[:fail_fast]
|
|
68
|
-
storage_options[:storage].store_map_failed_context_id(
|
|
69
|
-
storage_options[:map_id], child_context.context_id, storage_options[:parent_reactor_class_name]
|
|
70
|
-
)
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
result
|
|
74
|
-
end.compact
|
|
75
|
-
# rubocop:enable Metrics/BlockLength
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def self.link_contexts(child_context, parent_context)
|
|
79
|
-
child_context.parent_context = parent_context
|
|
80
|
-
child_context.root_context = parent_context.root_context || parent_context
|
|
81
|
-
child_context.inline_async_execution = parent_context.inline_async_execution
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def self.store_result(result, index, options)
|
|
85
|
-
value = result.success? ? result.value : { _error: result.error }
|
|
86
|
-
options[:storage].store_map_result(
|
|
87
|
-
options[:map_id], index, ContextSerializer.serialize_value(value), options[:parent_reactor_class_name],
|
|
88
|
-
strict_ordering: options[:strict_ordering]
|
|
89
|
-
)
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def self.finalize_execution(results, parent_context, step_name, parent_reactor_class_name, storage)
|
|
93
|
-
step_config = Object.const_get(parent_reactor_class_name).steps[step_name.to_sym]
|
|
94
|
-
final_result = apply_collect_block(results, step_config)
|
|
95
|
-
resume_parent_execution(parent_context, step_name, final_result, storage)
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
private_class_method :execute_all_elements, :store_result, :finalize_execution
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
end
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "sidekiq"
|
|
4
|
-
|
|
5
|
-
module RubyReactor
|
|
6
|
-
module SidekiqWorkers
|
|
7
|
-
class MapExecutionWorker
|
|
8
|
-
include ::Sidekiq::Worker
|
|
9
|
-
|
|
10
|
-
def perform(arguments)
|
|
11
|
-
RubyReactor::Map::Execution.perform(arguments)
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|