ruby_reactor 0.3.2 → 0.4.1

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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/.release-please-config.json +18 -0
  3. data/.release-please-manifest.json +3 -0
  4. data/.tool-versions +1 -0
  5. data/CHANGELOG.md +21 -0
  6. data/README.md +80 -4
  7. data/lib/ruby_reactor/context.rb +5 -2
  8. data/lib/ruby_reactor/context_serializer.rb +56 -3
  9. data/lib/ruby_reactor/dsl/reactor.rb +10 -1
  10. data/lib/ruby_reactor/executor/result_handler.rb +1 -12
  11. data/lib/ruby_reactor/executor.rb +7 -1
  12. data/lib/ruby_reactor/map/result_enumerator.rb +4 -3
  13. data/lib/ruby_reactor/rate_limit.rb +2 -2
  14. data/lib/ruby_reactor/reactor.rb +11 -4
  15. data/lib/ruby_reactor/sidekiq_workers/worker.rb +58 -1
  16. data/lib/ruby_reactor/storage/redis_adapter.rb +10 -3
  17. data/lib/ruby_reactor/storage/redis_locking.rb +17 -0
  18. data/lib/ruby_reactor/utils/backtrace_location.rb +37 -0
  19. data/lib/ruby_reactor/version.rb +1 -1
  20. data/lib/ruby_reactor/web/api.rb +68 -8
  21. data/lib/ruby_reactor/web/coordination_serializer.rb +180 -0
  22. data/lib/ruby_reactor/web/public/assets/index-CCnNVQy5.css +1 -0
  23. data/lib/ruby_reactor/web/public/assets/index-D7IBZvos.js +21 -0
  24. data/lib/ruby_reactor/web/public/index.html +2 -2
  25. data/lib/ruby_reactor.rb +7 -2
  26. metadata +11 -54
  27. data/documentation/DAG.md +0 -457
  28. data/documentation/README.md +0 -135
  29. data/documentation/async_reactors.md +0 -381
  30. data/documentation/composition.md +0 -199
  31. data/documentation/core_concepts.md +0 -676
  32. data/documentation/data_pipelines.md +0 -230
  33. data/documentation/examples/inventory_management.md +0 -748
  34. data/documentation/examples/order_processing.md +0 -380
  35. data/documentation/examples/payment_processing.md +0 -565
  36. data/documentation/getting_started.md +0 -242
  37. data/documentation/images/failed_order_processing.png +0 -0
  38. data/documentation/images/payment_workflow.png +0 -0
  39. data/documentation/interrupts.md +0 -163
  40. data/documentation/locks_and_semaphores.md +0 -459
  41. data/documentation/retry_configuration.md +0 -362
  42. data/documentation/testing.md +0 -994
  43. data/gui/.gitignore +0 -24
  44. data/gui/README.md +0 -73
  45. data/gui/eslint.config.js +0 -23
  46. data/gui/index.html +0 -13
  47. data/gui/package-lock.json +0 -5925
  48. data/gui/package.json +0 -46
  49. data/gui/postcss.config.js +0 -6
  50. data/gui/public/vite.svg +0 -1
  51. data/gui/src/App.css +0 -42
  52. data/gui/src/App.tsx +0 -51
  53. data/gui/src/assets/react.svg +0 -1
  54. data/gui/src/components/DagVisualizer.tsx +0 -424
  55. data/gui/src/components/Dashboard.tsx +0 -163
  56. data/gui/src/components/ErrorBoundary.tsx +0 -47
  57. data/gui/src/components/ReactorDetail.tsx +0 -135
  58. data/gui/src/components/StepInspector.tsx +0 -492
  59. data/gui/src/components/__tests__/DagVisualizer.test.tsx +0 -140
  60. data/gui/src/components/__tests__/ReactorDetail.test.tsx +0 -111
  61. data/gui/src/components/__tests__/StepInspector.test.tsx +0 -408
  62. data/gui/src/globals.d.ts +0 -7
  63. data/gui/src/index.css +0 -14
  64. data/gui/src/lib/utils.ts +0 -13
  65. data/gui/src/main.tsx +0 -14
  66. data/gui/src/test/setup.ts +0 -11
  67. data/gui/tailwind.config.js +0 -11
  68. data/gui/tsconfig.app.json +0 -28
  69. data/gui/tsconfig.json +0 -7
  70. data/gui/tsconfig.node.json +0 -26
  71. data/gui/vite.config.ts +0 -8
  72. data/gui/vitest.config.ts +0 -13
  73. data/lib/ruby_reactor/web/public/assets/index-VdeLgH9k.js +0 -19
  74. 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-VdeLgH9k.js"></script>
9
- <link rel="stylesheet" crossorigin href="./assets/index-_z-6BvuM.css">
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
- root_path = RubyReactor.root.to_s
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
- if line.start_with?(root_path)
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
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_reactor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Artur
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2026-05-16 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: dry-validation
@@ -89,57 +88,15 @@ executables: []
89
88
  extensions: []
90
89
  extra_rdoc_files: []
91
90
  files:
91
+ - ".release-please-config.json"
92
+ - ".release-please-manifest.json"
92
93
  - ".rspec"
93
94
  - ".rubocop.yml"
95
+ - ".tool-versions"
96
+ - CHANGELOG.md
94
97
  - CODE_OF_CONDUCT.md
95
98
  - README.md
96
99
  - Rakefile
97
- - documentation/DAG.md
98
- - documentation/README.md
99
- - documentation/async_reactors.md
100
- - documentation/composition.md
101
- - documentation/core_concepts.md
102
- - documentation/data_pipelines.md
103
- - documentation/examples/inventory_management.md
104
- - documentation/examples/order_processing.md
105
- - documentation/examples/payment_processing.md
106
- - documentation/getting_started.md
107
- - documentation/images/failed_order_processing.png
108
- - documentation/images/payment_workflow.png
109
- - documentation/interrupts.md
110
- - documentation/locks_and_semaphores.md
111
- - documentation/retry_configuration.md
112
- - documentation/testing.md
113
- - gui/.gitignore
114
- - gui/README.md
115
- - gui/eslint.config.js
116
- - gui/index.html
117
- - gui/package-lock.json
118
- - gui/package.json
119
- - gui/postcss.config.js
120
- - gui/public/vite.svg
121
- - gui/src/App.css
122
- - gui/src/App.tsx
123
- - gui/src/assets/react.svg
124
- - gui/src/components/DagVisualizer.tsx
125
- - gui/src/components/Dashboard.tsx
126
- - gui/src/components/ErrorBoundary.tsx
127
- - gui/src/components/ReactorDetail.tsx
128
- - gui/src/components/StepInspector.tsx
129
- - gui/src/components/__tests__/DagVisualizer.test.tsx
130
- - gui/src/components/__tests__/ReactorDetail.test.tsx
131
- - gui/src/components/__tests__/StepInspector.test.tsx
132
- - gui/src/globals.d.ts
133
- - gui/src/index.css
134
- - gui/src/lib/utils.ts
135
- - gui/src/main.tsx
136
- - gui/src/test/setup.ts
137
- - gui/tailwind.config.js
138
- - gui/tsconfig.app.json
139
- - gui/tsconfig.json
140
- - gui/tsconfig.node.json
141
- - gui/vite.config.ts
142
- - gui/vitest.config.ts
143
100
  - lib/ruby_reactor.rb
144
101
  - lib/ruby_reactor/configuration.rb
145
102
  - lib/ruby_reactor/context.rb
@@ -210,6 +167,7 @@ files:
210
167
  - lib/ruby_reactor/template/input.rb
211
168
  - lib/ruby_reactor/template/result.rb
212
169
  - lib/ruby_reactor/template/value.rb
170
+ - lib/ruby_reactor/utils/backtrace_location.rb
213
171
  - lib/ruby_reactor/utils/code_extractor.rb
214
172
  - lib/ruby_reactor/validation/base.rb
215
173
  - lib/ruby_reactor/validation/input_validator.rb
@@ -218,8 +176,9 @@ files:
218
176
  - lib/ruby_reactor/web/api.rb
219
177
  - lib/ruby_reactor/web/application.rb
220
178
  - lib/ruby_reactor/web/config.ru
221
- - lib/ruby_reactor/web/public/assets/index-VdeLgH9k.js
222
- - lib/ruby_reactor/web/public/assets/index-_z-6BvuM.css
179
+ - lib/ruby_reactor/web/coordination_serializer.rb
180
+ - lib/ruby_reactor/web/public/assets/index-CCnNVQy5.css
181
+ - lib/ruby_reactor/web/public/assets/index-D7IBZvos.js
223
182
  - lib/ruby_reactor/web/public/index.html
224
183
  - lib/ruby_reactor/web/public/vite.svg
225
184
  - llms-full.txt
@@ -233,7 +192,6 @@ metadata:
233
192
  homepage_uri: https://github.com/arturictus/ruby_reactor
234
193
  source_code_uri: https://github.com/arturictus/ruby_reactor
235
194
  changelog_uri: https://github.com/arturictus/ruby_reactor/blob/main/CHANGELOG.md
236
- post_install_message:
237
195
  rdoc_options: []
238
196
  require_paths:
239
197
  - lib
@@ -248,8 +206,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
248
206
  - !ruby/object:Gem::Version
249
207
  version: '0'
250
208
  requirements: []
251
- rubygems_version: 3.4.19
252
- signing_key:
209
+ rubygems_version: 3.6.9
253
210
  specification_version: 4
254
211
  summary: A dynamic, concurrent, dependency-resolving saga orchestrator for Ruby.
255
212
  test_files: []
data/documentation/DAG.md DELETED
@@ -1,457 +0,0 @@
1
- # DAG Execution and Saga Patterns in RubyReactor
2
-
3
- RubyReactor uses Directed Acyclic Graphs (DAGs) to manage step dependencies and implements saga patterns for reliable distributed transactions. This document explains how DAG execution works and how saga patterns ensure consistency across complex workflows.
4
-
5
- ## Directed Acyclic Graphs (DAGs)
6
-
7
- A DAG is a graph with directed edges and no cycles, ensuring that step dependencies can be resolved in a deterministic order.
8
-
9
- ### DAG Structure
10
-
11
- ```mermaid
12
- graph TD
13
- A[Step A] --> C[Step C]
14
- B[Step B] --> C
15
- C --> D[Step D]
16
- C --> E[Step E]
17
- D --> F[Step F]
18
- E --> F
19
-
20
- style A fill:#e1f5fe
21
- style B fill:#e1f5fe
22
- style C fill:#fff3e0
23
- style D fill:#e8f5e8
24
- style E fill:#e8f5e8
25
- style F fill:#ffebee
26
- ```
27
-
28
- **Legend:**
29
- - 🔵 Independent steps (can run in parallel)
30
- - 🟡 Dependent steps (wait for prerequisites)
31
- - 🟢 Ready to execute
32
- - 🔴 Final step
33
-
34
- ### DAG Execution Algorithm
35
-
36
- ```mermaid
37
- graph TD
38
- A[Start Execution] --> B[Build Dependency Graph]
39
- B --> C[Identify Ready Steps<br/>no unmet dependencies]
40
- C --> D{Ready Steps<br/>Available?}
41
- D -->|No| E[Execution Complete]
42
- D -->|Yes| F[Execute Ready Steps<br/>in Parallel]
43
- F --> G[Update Dependencies<br/>Mark steps complete]
44
- G --> H[Collect Results]
45
- H --> I{Execution<br/>Successful?}
46
- I -->|Yes| C
47
- I -->|No| J[Initiate Saga Compensation]
48
- J --> K[Execution Failed]
49
- ```
50
-
51
- ### Dependency Resolution
52
-
53
- ```mermaid
54
- graph TD
55
- A[Step Dependencies] --> B[Topological Sort]
56
- B --> C[Execution Order<br/>A → B → C → D]
57
- C --> D[Parallel Execution<br/>Where Possible]
58
-
59
- subgraph "Level 1"
60
- A1[Independent Steps]
61
- end
62
-
63
- subgraph "Level 2"
64
- B1[Steps depending on Level 1]
65
- end
66
-
67
- subgraph "Level 3"
68
- C1[Steps depending on Level 2]
69
- end
70
- ```
71
-
72
- ## Saga Patterns
73
-
74
- RubyReactor implements saga patterns to ensure consistency across distributed operations. Sagas provide transactional semantics for long-running business processes.
75
-
76
- ### Saga Execution Flow
77
-
78
- ```mermaid
79
- graph TD
80
- A[Saga Initiated] --> B[Execute Step 1]
81
- B --> C{Step 1<br/>Success?}
82
- C -->|Yes| D[Execute Step 2]
83
- C -->|No| E[Compensation Step 1]
84
- D --> F{Step 2<br/>Success?}
85
- F -->|Yes| G[Execute Step 3]
86
- F -->|No| H[Compensate Step 2, Undo Step 1]
87
- G --> I{Step 3<br/>Success?}
88
- I -->|Yes| J[Saga Complete]
89
- I -->|No| K[Compensate Step 3<br/>Then Undo Steps 2 and 1]
90
- H --> L[Saga Failed]
91
- K --> L
92
- E --> L
93
-
94
- style A fill:#e3f2fd
95
- style J fill:#e8f5e8
96
- style L fill:#ffebee
97
- ```
98
-
99
- ### Compensation Strategies
100
-
101
- #### Backward Recovery (Rollback)
102
-
103
- ```mermaid
104
- graph TD
105
- A[Forward Execution] --> B[Step A Success]
106
- B --> C[Step B Success]
107
- C --> D[Step C Fails]
108
- D --> E[Start Compensation]
109
- E --> F[Compensate C]
110
- F --> G[Undo B]
111
- G --> H[Undo A]
112
- H --> I[Consistent State Restored]
113
-
114
- style A fill:#e3f2fd
115
- style I fill:#e8f5e8
116
- style D fill:#ffebee
117
- ```
118
-
119
- #### Forward Recovery (Retry)
120
-
121
- ```mermaid
122
- graph TD
123
- A[Step Fails] --> B{Can Retry?}
124
- B -->|Yes| C[Calculate Backoff]
125
- C --> D[Schedule Retry]
126
- D --> E[Retry Execution]
127
- E --> F{Retry<br/>Success?}
128
- F -->|Yes| G[Continue Saga]
129
- F -->|No| B
130
- B -->|No| H[Compensation Required]
131
-
132
- style G fill:#e8f5e8
133
- style H fill:#ffebee
134
- ```
135
-
136
- ## Complex Saga Scenarios
137
-
138
- ### Order Processing Saga
139
-
140
- ```mermaid
141
- graph TD
142
- A[Order Submitted] --> B[Validate Order]
143
- B --> C{Valid?}
144
- C -->|No| D[Saga Failed]
145
- C -->|Yes| E[Reserve Inventory]
146
- E --> F{Reserved?}
147
- F -->|No| G[Saga Failed]
148
- F -->|Yes| H[Process Payment]
149
- H --> I{Payment OK?}
150
- I -->|No| J[Release Inventory<br/>Compensation]
151
- I -->|Yes| K[Update Order Status]
152
- K --> L[Send Confirmation]
153
- L --> M[Saga Complete]
154
-
155
- J --> D
156
- G --> D
157
-
158
- style A fill:#e3f2fd
159
- style M fill:#e8f5e8
160
- style D fill:#ffebee
161
- ```
162
-
163
-
164
- ## DAG + Saga Integration
165
-
166
- RubyReactor combines DAG execution with saga patterns for complex workflows:
167
-
168
- ```mermaid
169
- graph TD
170
- subgraph "DAG Execution"
171
- A1[Build Graph] --> B1[Resolve Dependencies]
172
- B1 --> C1[Execute in Order]
173
- end
174
-
175
- subgraph "Saga Pattern"
176
- D1[Monitor Execution] --> E1{Step Fails?}
177
- E1 -->|No| F1[Continue]
178
- E1 -->|Yes| G1[Trigger Compensation]
179
- end
180
-
181
- subgraph "Retry Mechanism"
182
- H1[Failed Step] --> I1{Can Retry?}
183
- I1 -->|Yes| J1[Requeue Job]
184
- I1 -->|No| K1[Final Compensation]
185
- end
186
-
187
- C1 --> D1
188
- G1 --> H1
189
- J1 --> A1
190
-
191
- style F1 fill:#e8f5e8
192
- style K1 fill:#ffebee
193
- ```
194
-
195
- ## Execution States
196
-
197
- ### Step States
198
-
199
- ```mermaid
200
- stateDiagram-v2
201
- [*] --> Pending
202
- Pending --> Running
203
- Running --> Completed
204
- Running --> Failed
205
- Failed --> Compensating
206
- Compensating --> Compensated
207
- Compensated --> [*]
208
- Failed --> Retrying
209
- Retrying --> Pending
210
- ```
211
-
212
- ### Saga States
213
-
214
- ```mermaid
215
- stateDiagram-v2
216
- [*] --> Initiated
217
- Initiated --> Executing
218
- Executing --> Completed
219
- Executing --> Failing
220
- Failing --> Compensating
221
- Compensating --> Failed
222
- Failed --> [*]
223
- Completed --> [*]
224
- ```
225
-
226
- ## Error Handling Patterns
227
-
228
- ### Cascading Compensation
229
-
230
- ```mermaid
231
- graph TD
232
- A[Root Cause Failure] --> B[Step N Fails]
233
- B --> C[Mark Step N for Compensation]
234
- C --> D[Stop Downstream Steps]
235
- D --> E[Execute Compensation Chain]
236
- E --> F[Step N-1 Compensation]
237
- F --> G[Step N-2 Compensation]
238
- G --> H[...continue to Step 1]
239
- H --> I[Consistent State Achieved]
240
-
241
- style A fill:#ffebee
242
- style I fill:#e8f5e8
243
- ```
244
-
245
- ### Partial Success Handling
246
-
247
- ```mermaid
248
- graph TD
249
- A[Multi-Step Process] --> B[Step 1 Success]
250
- B --> C[Step 2 Success]
251
- C --> D[Step 3 Fails]
252
- D --> E{Essential<br/>Step?}
253
- E -->|Yes| F[Full Compensation Required]
254
- E -->|No| G[Partial Success Acceptable]
255
- G --> H[Continue with Successful Steps]
256
- H --> I[Manual Intervention for Failed Step]
257
-
258
- style G fill:#fff3e0
259
- style I fill:#fff3e0
260
- ```
261
-
262
- ## Performance Considerations
263
-
264
- ### Parallel Execution in DAGs
265
-
266
- ```mermaid
267
- graph TD
268
- A[Level 1<br/>Parallel Steps] --> B[Level 2<br/>Parallel Steps]
269
- B --> C[Level 3<br/>Parallel Steps]
270
-
271
- subgraph "Level 1 (3 steps)"
272
- A1[Step A] & A2[Step B] & A3[Step C]
273
- end
274
-
275
- subgraph "Level 2 (2 steps)"
276
- B1[Step D] & B2[Step E]
277
- end
278
-
279
- subgraph "Level 3 (1 step)"
280
- C1[Step F]
281
- end
282
-
283
- A1 --> B1
284
- A2 --> B1
285
- A3 --> B2
286
- B1 --> C1
287
- B2 --> C1
288
- ```
289
-
290
- ### Saga Overhead
291
-
292
- ```mermaid
293
- graph TD
294
- A[Normal Execution] --> B[Fast Path<br/>No Compensation]
295
- C[Saga Execution] --> D[State Tracking<br/>Compensation Logic]
296
- D --> E[Increased Complexity]
297
-
298
- A --> F[Better Performance]
299
- C --> G[Reliability Benefits]
300
-
301
- style F fill:#e8f5e8
302
- style G fill:#e8f5e8
303
- ```
304
-
305
- ## Monitoring and Observability
306
-
307
- ### Saga Metrics
308
-
309
- ```mermaid
310
- graph TD
311
- A[Saga Metrics] --> B[Completion Rate]
312
- A --> C[Average Duration]
313
- A --> D[Compensation Frequency]
314
- A --> E[Retry Attempts]
315
- A --> F[Failure Patterns]
316
-
317
- B --> G[Business Health]
318
- C --> H[Performance Monitoring]
319
- D --> I[Reliability Insights]
320
- E --> J[Resilience Metrics]
321
- F --> K[Root Cause Analysis]
322
- ```
323
-
324
- ### DAG Execution Monitoring
325
-
326
- ```mermaid
327
- graph TD
328
- A[DAG Monitoring] --> B[Step Dependencies]
329
- A --> C[Execution Order]
330
- A --> D[Parallel Execution]
331
- A --> E[Bottleneck Identification]
332
-
333
- B --> F[Dependency Health]
334
- C --> G[Execution Flow]
335
- D --> H[Concurrency Optimization]
336
- E --> I[Performance Tuning]
337
- ```
338
-
339
- ## Best Practices
340
-
341
- ### DAG Design
342
-
343
- 1. **Keep it Simple**: Minimize dependencies to maximize parallelism
344
- 2. **Clear Dependencies**: Make step relationships explicit
345
- 3. **Avoid Cycles**: Ensure DAG remains acyclic
346
- 4. **Test Execution Order**: Verify topological sort produces expected order
347
-
348
- ### Saga Implementation
349
-
350
- 1. **Idempotent Operations**: Design steps to be safely retryable
351
- 2. **Compensation Logic**: Always implement proper undo operations
352
- 3. **State Tracking**: Maintain sufficient state for compensation
353
- 4. **Timeout Handling**: Set appropriate timeouts for long-running sagas
354
-
355
- ### Error Handling
356
-
357
- 1. **Graceful Degradation**: Handle partial failures appropriately
358
- 2. **Circuit Breakers**: Prevent cascade failures
359
- 3. **Monitoring**: Track saga health and failure patterns
360
- 4. **Recovery Procedures**: Document manual recovery processes
361
-
362
- ## Implementation Examples
363
-
364
- ### Simple DAG with Saga
365
-
366
- ```ruby
367
- class OrderProcessingReactor < RubyReactor::Reactor
368
- async true
369
-
370
- step :validate_order do
371
- run { validate_order_logic }
372
- end
373
-
374
- step :reserve_inventory do
375
- argument :order, result(:validate_order)
376
- run do |args, _context|
377
- reserve_inventory_logic(args[:order])
378
- end
379
-
380
- compensate do
381
- # Release reservation
382
- release_inventory_logic
383
- end
384
- end
385
-
386
- step :process_payment do
387
- argument :inventory_result, result(:reserve_inventory)
388
- run do |args, _context|
389
- process_payment_logic(args[:inventory_result])
390
- end
391
-
392
- compensate do
393
- # Refund payment
394
- refund_payment_logic
395
- end
396
- end
397
-
398
- step :confirm_order do
399
- argument :payment_result, result(:process_payment)
400
- run do |args, _context|
401
- confirm_order_logic(args[:payment_result])
402
- end
403
- end
404
- end
405
- ```
406
-
407
- ### Complex DAG with Parallel Execution
408
-
409
- ```ruby
410
- class ComplexWorkflowReactor < RubyReactor::Reactor
411
- async true
412
-
413
- # Level 1 - Independent steps
414
- step :validate_input do
415
- run { validate_input_logic }
416
- end
417
-
418
- step :check_permissions do
419
- run { check_permissions_logic }
420
- end
421
-
422
- # Level 2 - Depends on level 1
423
- step :process_data do
424
- argument :validation_result, result(:validate_input)
425
- argument :permissions_result, result(:check_permissions)
426
- run do |args, _context|
427
- process_data_logic(args[:validation_result], args[:permissions_result])
428
- end
429
- end
430
-
431
- # Level 3 - Parallel steps depending on level 2
432
- step :send_notification do
433
- argument :data_result, result(:process_data)
434
- run do |args, _context|
435
- send_notification_logic(args[:data_result])
436
- end
437
- end
438
-
439
- step :update_audit_log do
440
- argument :data_result, result(:process_data)
441
- run do |args, _context|
442
- update_audit_log_logic(args[:data_result])
443
- end
444
- end
445
-
446
- # Level 4 - Depends on level 3
447
- step :cleanup do
448
- argument :notification_result, result(:send_notification)
449
- argument :audit_result, result(:update_audit_log)
450
- run do |args, _context|
451
- cleanup_logic(args[:notification_result], args[:audit_result])
452
- end
453
- end
454
- end
455
- ```
456
-
457
- This DAG allows `send_notification` and `update_audit_log` to execute in parallel after `process_data` completes, demonstrating how RubyReactor maximizes concurrency while maintaining dependency ordering