ruby_reactor 0.8.4 → 0.8.5

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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/.release-please-manifest.json +1 -1
  3. data/.specify/feature.json +1 -1
  4. data/CHANGELOG.md +196 -0
  5. data/CLAUDE.md +1 -1
  6. data/README.md +47 -11
  7. data/lib/ruby_reactor/dsl/async_macros.rb +30 -1
  8. data/lib/ruby_reactor/dsl/async_reactor_builder.rb +12 -6
  9. data/lib/ruby_reactor/dsl/compose_builder.rb +12 -6
  10. data/lib/ruby_reactor/dsl/interrupt_builder.rb +1 -3
  11. data/lib/ruby_reactor/dsl/map_builder.rb +0 -2
  12. data/lib/ruby_reactor/dsl/step_builder.rb +91 -19
  13. data/lib/ruby_reactor/error/argument_resolution_error.rb +19 -0
  14. data/lib/ruby_reactor/error/rescuable.rb +28 -0
  15. data/lib/ruby_reactor/executor/compensation_manager.rb +30 -26
  16. data/lib/ruby_reactor/executor/result_handler.rb +18 -16
  17. data/lib/ruby_reactor/executor/step_coordination.rb +11 -8
  18. data/lib/ruby_reactor/executor/step_executor.rb +59 -49
  19. data/lib/ruby_reactor/executor.rb +38 -4
  20. data/lib/ruby_reactor/map/collector.rb +21 -11
  21. data/lib/ruby_reactor/map/dispatcher.rb +29 -3
  22. data/lib/ruby_reactor/map/element_executor.rb +9 -3
  23. data/lib/ruby_reactor/map/helpers.rb +32 -2
  24. data/lib/ruby_reactor/map/result_enumerator.rb +18 -12
  25. data/lib/ruby_reactor/reactor.rb +24 -0
  26. data/lib/ruby_reactor/rspec/matchers.rb +19 -3
  27. data/lib/ruby_reactor/step/compose_step.rb +7 -1
  28. data/lib/ruby_reactor/step/map_step.rb +109 -4
  29. data/lib/ruby_reactor/step.rb +7 -0
  30. data/lib/ruby_reactor/step_worker.rb +46 -22
  31. data/lib/ruby_reactor/storage/adapter.rb +4 -0
  32. data/lib/ruby_reactor/storage/redis_adapter.rb +9 -0
  33. data/lib/ruby_reactor/storage/redis_reactor_scan.rb +1 -1
  34. data/lib/ruby_reactor/version.rb +1 -1
  35. data/lib/ruby_reactor/web/api.rb +1 -1
  36. data/lib/ruby_reactor/web/public/assets/{index-CeZU-ESu.js → index-CQbgHtd0.js} +10 -10
  37. data/lib/ruby_reactor/web/public/index.html +1 -1
  38. data/lib/ruby_reactor/worker.rb +3 -1
  39. data/lib/ruby_reactor.rb +17 -6
  40. data/specs/007-execution-flow-analysis/analysis/README.md +147 -0
  41. data/specs/007-execution-flow-analysis/analysis/execution-order.md +359 -0
  42. data/specs/007-execution-flow-analysis/analysis/findings-and-options.md +502 -0
  43. data/specs/007-execution-flow-analysis/analysis/invariants.md +109 -0
  44. data/specs/007-execution-flow-analysis/checklists/requirements.md +39 -0
  45. data/specs/007-execution-flow-analysis/contracts/report-structure.md +71 -0
  46. data/specs/007-execution-flow-analysis/data-model.md +83 -0
  47. data/specs/007-execution-flow-analysis/evidence/harness.rb +229 -0
  48. data/specs/007-execution-flow-analysis/evidence/output.txt +333 -0
  49. data/specs/007-execution-flow-analysis/evidence/probes/01_plain.rb +122 -0
  50. data/specs/007-execution-flow-analysis/evidence/probes/02_compose.rb +182 -0
  51. data/specs/007-execution-flow-analysis/evidence/probes/03_map.rb +232 -0
  52. data/specs/007-execution-flow-analysis/evidence/probes/04_async.rb +132 -0
  53. data/specs/007-execution-flow-analysis/evidence/probes/05_background.rb +58 -0
  54. data/specs/007-execution-flow-analysis/evidence/probes/06_coordination.rb +158 -0
  55. data/specs/007-execution-flow-analysis/evidence/probes/07_interrupts_manual.rb +185 -0
  56. data/specs/007-execution-flow-analysis/evidence/run.rb +15 -0
  57. data/specs/007-execution-flow-analysis/plan.md +127 -0
  58. data/specs/007-execution-flow-analysis/quickstart.md +51 -0
  59. data/specs/007-execution-flow-analysis/research.md +202 -0
  60. data/specs/007-execution-flow-analysis/spec.md +270 -0
  61. data/specs/007-execution-flow-analysis/tasks.md +257 -0
  62. data/specs/008-rollback-reliability/checklists/requirements.md +43 -0
  63. data/specs/008-rollback-reliability/contracts/api-surface.md +126 -0
  64. data/specs/008-rollback-reliability/contracts/rollback-semantics.md +76 -0
  65. data/specs/008-rollback-reliability/data-model.md +139 -0
  66. data/specs/008-rollback-reliability/plan.md +233 -0
  67. data/specs/008-rollback-reliability/quickstart.md +105 -0
  68. data/specs/008-rollback-reliability/research.md +653 -0
  69. data/specs/008-rollback-reliability/spec.md +561 -0
  70. data/specs/008-rollback-reliability/tasks.md +1110 -0
  71. data/specs/future_improvements.md +48 -0
  72. metadata +35 -2
@@ -248,3 +248,51 @@ Direction:
248
248
 
249
249
  Spec: compose → fan-out map, with and without a park after the map. The root completes either
250
250
  way.
251
+
252
+ ## Rollback follow-ups (008)
253
+
254
+ Raised while implementing specs/008-rollback-reliability. None blocks it.
255
+
256
+ - **Sweeper re-enqueues in-progress inline runs.** `RubyReactor::Sweeper` re-enqueues any
257
+ top-level context that is `running` with no `async:` lock. A run still executing in the
258
+ caller's process never holds that lock, so a sweep during it enqueues a worker that resumes the
259
+ same run forward. Pre-existing; 008 only keeps `aborted` runs out of it. Direction: mark
260
+ caller-process runs (the `inline_async_execution` inverse) so the sweeper skips them until they
261
+ are stale by a timestamp, or give them their own liveness lock.
262
+ - **Map-level `undo_all` override.** Map rollback always replays each element's own step `undo`s.
263
+ A bulk refund API may want one call for all elements instead. Direction: an optional
264
+ `undo_all { |completed_results| ... }` on `map` that replaces the per-element replay.
265
+ - **Rollback fan-out for very large maps.** Map rollback is serial, in the process that detected
266
+ the failure, so its time is linear in the number of completed elements (10,000 elements take
267
+ about a minute in the test suite). Direction: enqueue one rollback job per element (or per
268
+ batch) and resolve the parent's failure once they report back.
269
+ - **A resume for a second pending interrupt while the first is executing.** A reactor paused at
270
+ several ready interrupts takes their resumes one at a time: each accepted resume marks the run
271
+ `running` (008 FR-032), and the run pauses again at the interrupts still pending. A resume that
272
+ arrives for another pending interrupt while the first resume is still executing is rejected
273
+ ("the reactor is running"). Interrupt steps have no body, so that window is short, but a caller
274
+ resuming two interrupts at once can hit it. Direction: accept it for an interrupt that has not
275
+ executed yet (store its payload and let the running resume pick it up), or return a retryable
276
+ error.
277
+ - **An interrupted `compensate` of the failing step is not re-run.** An interruption (signal, exit,
278
+ out of memory) during the failing step's own `compensate` leaves the run `aborted`. A manual
279
+ `Reactor.undo(id)` undoes the completed steps but never re-runs that `compensate`, so the step
280
+ can stay half-compensated. Pre-existing (008 R-08). Direction: record the failing step on the
281
+ aborted run and have manual undo re-run its `compensate` before the undo stack.
282
+ - **Recover a resume contended on a lock.** An inline `continue` that cannot take the reactor's
283
+ `with_lock` or `with_semaphore` raises its `AcquisitionError` and leaves the run `paused`; the
284
+ caller has to retry it (008 review, 2026-09-30). A webhook sender that does not retry loses the
285
+ resume. Direction:
286
+ - Validate the payload first, synchronously in the calling process, as `resume: :background`
287
+ does today. An invalid payload returns its validation failure to the caller (the webhook),
288
+ and nothing is stored or enqueued.
289
+ - Only a valid payload is stored and handed off. On contention, mark the run `running` and give
290
+ the resume to a worker. The worker snoozes on the contended lock without spending retries and
291
+ resumes once the lock is free. The deferred resume never re-validates the payload, so it
292
+ cannot fail on validation after the caller was told it was accepted.
293
+ - `continue` returns a `DispatchResult` instead of raising, and a second `continue` is rejected
294
+ as for any running resume.
295
+ - **Two resumes in the same instant.** Two `continue` calls that both read `paused` before either
296
+ saves `running` are separated only by the per-run context lock, which inline Sidekiq testing
297
+ skips. Accepted for now (008 review, 2026-09-27). Direction: claim the resume with an atomic
298
+ status compare-and-set.
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.8.4
4
+ version: 0.8.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Artur
@@ -169,6 +169,7 @@ files:
169
169
  - lib/ruby_reactor/dsl/step_builder.rb
170
170
  - lib/ruby_reactor/dsl/template_helpers.rb
171
171
  - lib/ruby_reactor/dsl/validation_helpers.rb
172
+ - lib/ruby_reactor/error/argument_resolution_error.rb
172
173
  - lib/ruby_reactor/error/async_result_pending.rb
173
174
  - lib/ruby_reactor/error/async_wait_timeout_error.rb
174
175
  - lib/ruby_reactor/error/base.rb
@@ -180,6 +181,7 @@ files:
180
181
  - lib/ruby_reactor/error/execution_parked.rb
181
182
  - lib/ruby_reactor/error/input_validation_error.rb
182
183
  - lib/ruby_reactor/error/reactor_contention_park.rb
184
+ - lib/ruby_reactor/error/rescuable.rb
183
185
  - lib/ruby_reactor/error/schema_version_error.rb
184
186
  - lib/ruby_reactor/error/step_contention_park.rb
185
187
  - lib/ruby_reactor/error/step_failure_error.rb
@@ -264,7 +266,7 @@ files:
264
266
  - lib/ruby_reactor/web/config.ru
265
267
  - lib/ruby_reactor/web/coordination_serializer.rb
266
268
  - lib/ruby_reactor/web/public/assets/index-BQvIWPdx.css
267
- - lib/ruby_reactor/web/public/assets/index-CeZU-ESu.js
269
+ - lib/ruby_reactor/web/public/assets/index-CQbgHtd0.js
268
270
  - lib/ruby_reactor/web/public/index.html
269
271
  - lib/ruby_reactor/web/public/vite.svg
270
272
  - lib/ruby_reactor/worker.rb
@@ -279,6 +281,37 @@ files:
279
281
  - specs/006-step-retry-declarations/research.md
280
282
  - specs/006-step-retry-declarations/spec.md
281
283
  - specs/006-step-retry-declarations/tasks.md
284
+ - specs/007-execution-flow-analysis/analysis/README.md
285
+ - specs/007-execution-flow-analysis/analysis/execution-order.md
286
+ - specs/007-execution-flow-analysis/analysis/findings-and-options.md
287
+ - specs/007-execution-flow-analysis/analysis/invariants.md
288
+ - specs/007-execution-flow-analysis/checklists/requirements.md
289
+ - specs/007-execution-flow-analysis/contracts/report-structure.md
290
+ - specs/007-execution-flow-analysis/data-model.md
291
+ - specs/007-execution-flow-analysis/evidence/harness.rb
292
+ - specs/007-execution-flow-analysis/evidence/output.txt
293
+ - specs/007-execution-flow-analysis/evidence/probes/01_plain.rb
294
+ - specs/007-execution-flow-analysis/evidence/probes/02_compose.rb
295
+ - specs/007-execution-flow-analysis/evidence/probes/03_map.rb
296
+ - specs/007-execution-flow-analysis/evidence/probes/04_async.rb
297
+ - specs/007-execution-flow-analysis/evidence/probes/05_background.rb
298
+ - specs/007-execution-flow-analysis/evidence/probes/06_coordination.rb
299
+ - specs/007-execution-flow-analysis/evidence/probes/07_interrupts_manual.rb
300
+ - specs/007-execution-flow-analysis/evidence/run.rb
301
+ - specs/007-execution-flow-analysis/plan.md
302
+ - specs/007-execution-flow-analysis/quickstart.md
303
+ - specs/007-execution-flow-analysis/research.md
304
+ - specs/007-execution-flow-analysis/spec.md
305
+ - specs/007-execution-flow-analysis/tasks.md
306
+ - specs/008-rollback-reliability/checklists/requirements.md
307
+ - specs/008-rollback-reliability/contracts/api-surface.md
308
+ - specs/008-rollback-reliability/contracts/rollback-semantics.md
309
+ - specs/008-rollback-reliability/data-model.md
310
+ - specs/008-rollback-reliability/plan.md
311
+ - specs/008-rollback-reliability/quickstart.md
312
+ - specs/008-rollback-reliability/research.md
313
+ - specs/008-rollback-reliability/spec.md
314
+ - specs/008-rollback-reliability/tasks.md
282
315
  - specs/future_improvements.md
283
316
  - specs/scoped_rspec_matchers.md
284
317
  - specs/specs-inputs-by-method-md-piped-wigderson.md