ruby_reactor 0.8.2 → 0.8.4
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/.claude/skills/speckit-review/SKILL.md +324 -0
- data/.release-please-manifest.json +1 -1
- data/.specify/extensions.yml +10 -0
- data/.specify/feature.json +1 -1
- data/.specify/workflows/speckit/workflow.yml +13 -1
- data/.specify/workflows/workflow-registry.json +2 -2
- data/CHANGELOG.md +94 -0
- data/CLAUDE.md +2 -2
- data/README.md +128 -93
- data/lib/ruby_reactor/adapters/active_job/router.rb +19 -0
- data/lib/ruby_reactor/adapters/sidekiq/router.rb +21 -0
- data/lib/ruby_reactor/context.rb +26 -0
- data/lib/ruby_reactor/context_serializer.rb +4 -2
- data/lib/ruby_reactor/dsl/async_reactor_builder.rb +3 -6
- data/lib/ruby_reactor/dsl/compose_builder.rb +3 -10
- data/lib/ruby_reactor/dsl/interrupt_builder.rb +14 -0
- data/lib/ruby_reactor/dsl/lockable.rb +76 -21
- data/lib/ruby_reactor/dsl/reactor.rb +8 -11
- data/lib/ruby_reactor/dsl/retryable.rb +45 -0
- data/lib/ruby_reactor/dsl/step_builder.rb +150 -13
- data/lib/ruby_reactor/error/async_result_pending.rb +1 -1
- data/lib/ruby_reactor/error/execution_parked.rb +16 -0
- data/lib/ruby_reactor/error/reactor_contention_park.rb +26 -0
- data/lib/ruby_reactor/error/step_contention_park.rb +26 -0
- data/lib/ruby_reactor/error/undeclared_input_error.rb +13 -0
- data/lib/ruby_reactor/executor/async_step_dispatch.rb +109 -3
- data/lib/ruby_reactor/executor/compensation_manager.rb +99 -17
- data/lib/ruby_reactor/executor/ordered_lock_support.rb +76 -44
- data/lib/ruby_reactor/executor/result_handler.rb +34 -13
- data/lib/ruby_reactor/executor/retry_manager.rb +20 -13
- data/lib/ruby_reactor/executor/step_coordination.rb +788 -0
- data/lib/ruby_reactor/executor/step_executor.rb +115 -11
- data/lib/ruby_reactor/executor.rb +90 -20
- data/lib/ruby_reactor/map/element_executor.rb +24 -2
- data/lib/ruby_reactor/map/helpers.rb +35 -11
- data/lib/ruby_reactor/max_retries_exhausted_failure.rb +2 -2
- data/lib/ruby_reactor/open_telemetry.rb +61 -24
- data/lib/ruby_reactor/retry_context.rb +31 -2
- data/lib/ruby_reactor/rspec/helpers.rb +15 -0
- data/lib/ruby_reactor/rspec/matchers.rb +92 -0
- data/lib/ruby_reactor/rspec/test_subject.rb +9 -5
- data/lib/ruby_reactor/step/async_reactor_step.rb +46 -26
- data/lib/ruby_reactor/step/compose_step.rb +22 -7
- data/lib/ruby_reactor/step/input_contract.rb +5 -0
- data/lib/ruby_reactor/step/inputs.rb +57 -0
- data/lib/ruby_reactor/step/map_step.rb +32 -22
- data/lib/ruby_reactor/step.rb +59 -11
- data/lib/ruby_reactor/step_sweeper.rb +29 -1
- data/lib/ruby_reactor/step_worker.rb +260 -37
- data/lib/ruby_reactor/version.rb +1 -1
- data/lib/ruby_reactor/web/api.rb +72 -7
- data/lib/ruby_reactor/web/coordination_serializer.rb +120 -2
- data/lib/ruby_reactor/web/public/assets/{index-Dw4KV4QY.js → index-CeZU-ESu.js} +9 -9
- data/lib/ruby_reactor/web/public/index.html +1 -1
- data/lib/ruby_reactor/worker.rb +56 -30
- data/lib/ruby_reactor.rb +30 -6
- data/specs/{004-inheritable-step-class → 006-step-retry-declarations}/checklists/requirements.md +10 -9
- data/specs/006-step-retry-declarations/contracts/dsl-surface.md +89 -0
- data/specs/006-step-retry-declarations/data-model.md +58 -0
- data/specs/006-step-retry-declarations/plan.md +187 -0
- data/specs/006-step-retry-declarations/quickstart.md +80 -0
- data/specs/006-step-retry-declarations/research.md +194 -0
- data/specs/006-step-retry-declarations/spec.md +453 -0
- data/specs/006-step-retry-declarations/tasks.md +382 -0
- data/specs/future_improvements.md +250 -0
- data/specs/specs-inputs-by-method-md-piped-wigderson.md +77 -0
- metadata +20 -28
- data/specs/002-step-input-contracts/checklists/requirements.md +0 -49
- data/specs/002-step-input-contracts/contracts/dsl-surface.md +0 -193
- data/specs/002-step-input-contracts/data-model.md +0 -115
- data/specs/002-step-input-contracts/plan.md +0 -165
- data/specs/002-step-input-contracts/quickstart.md +0 -170
- data/specs/002-step-input-contracts/research.md +0 -233
- data/specs/002-step-input-contracts/spec.md +0 -359
- data/specs/002-step-input-contracts/tasks.md +0 -367
- data/specs/004-inheritable-step-class/contracts/step-lifecycle.md +0 -85
- data/specs/004-inheritable-step-class/data-model.md +0 -116
- data/specs/004-inheritable-step-class/plan.md +0 -174
- data/specs/004-inheritable-step-class/quickstart.md +0 -112
- data/specs/004-inheritable-step-class/research.md +0 -308
- data/specs/004-inheritable-step-class/spec.md +0 -316
- data/specs/004-inheritable-step-class/tasks.md +0 -258
- data/specs/active_job.md +0 -259
- data/specs/deferred-003-step-lock-declarations/checklists/requirements.md +0 -51
- data/specs/deferred-003-step-lock-declarations/contracts/dsl-surface.md +0 -154
- data/specs/deferred-003-step-lock-declarations/data-model.md +0 -131
- data/specs/deferred-003-step-lock-declarations/plan.md +0 -166
- data/specs/deferred-003-step-lock-declarations/quickstart.md +0 -169
- data/specs/deferred-003-step-lock-declarations/research.md +0 -196
- data/specs/deferred-003-step-lock-declarations/spec.md +0 -447
- data/specs/deferred-003-step-lock-declarations/tasks.md +0 -572
- data/specs/possible_feature.md +0 -22
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Quickstart: Validating Step-Scoped Retry Declarations
|
|
2
|
+
|
|
3
|
+
The API is in [contracts/dsl-surface.md](contracts/dsl-surface.md) and the resolution rules
|
|
4
|
+
are in [data-model.md](data-model.md).
|
|
5
|
+
|
|
6
|
+
## Prerequisites
|
|
7
|
+
|
|
8
|
+
- Ruby >= 3.0, `bundle install`
|
|
9
|
+
- Redis reachable by the suite (Constitution III): `docker compose up -d redis` or a local
|
|
10
|
+
`redis-server`
|
|
11
|
+
- For the demo: `docker compose up` (see the constitution, Principle VI §4)
|
|
12
|
+
|
|
13
|
+
## Phase A: `retry_defaults` removed (validate before starting Phase B)
|
|
14
|
+
|
|
15
|
+
1. The removal error fires at definition time:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
bundle exec ruby -Ilib -e 'require "ruby_reactor"; Class.new(RubyReactor::Reactor) { retry_defaults max_attempts: 3 }'
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Expected: `RubyReactor::Error::DeprecatedDslError`, with a message pointing to step-level
|
|
22
|
+
`retries`.
|
|
23
|
+
|
|
24
|
+
2. No references remain outside the removal stub and its spec:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
grep -rn "retry_defaults" lib spec demo_app README.md documentation llms*.txt
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Expected: only `lib/ruby_reactor/dsl/reactor.rb` (the stub) and the spec asserting it
|
|
31
|
+
raises.
|
|
32
|
+
|
|
33
|
+
3. The full suite and lint are green:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
bundle exec rspec && bundle exec rubocop
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Phase B: `retries` on step classes
|
|
40
|
+
|
|
41
|
+
Run the feature specs, then the full suite:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
bundle exec rspec spec/ruby_reactor/step_retries/
|
|
45
|
+
bundle exec rspec && bundle exec rubocop
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
What the feature spec must show (each maps to a spec story):
|
|
49
|
+
|
|
50
|
+
| Scenario | Expected | Spec |
|
|
51
|
+
| --- | --- | --- |
|
|
52
|
+
| Class declares 3 attempts, body fails twice, reactor has no wiring | success on attempt 3 | US2 |
|
|
53
|
+
| Same class, body always fails | `MaxRetriesExhaustedFailure`, 3 attempts, compensation runs | US2 |
|
|
54
|
+
| Inline `retries` vs class `retries`, same values and failures | same attempts, delays, outcome | US3 |
|
|
55
|
+
| Class `retries` + step block `retries` | `ValidationError` at reactor definition | US4 |
|
|
56
|
+
| Class `retries max_attempts: 1` | not retried | US4 |
|
|
57
|
+
| Same class under `background all: true` (drained) | attempts requeued, same count | US5 |
|
|
58
|
+
| Same class as `async_step` | `StepWorker` honors the class policy | US5 |
|
|
59
|
+
| Subclass without / with its own `retries` | inherits / overrides; parent unchanged | US6 |
|
|
60
|
+
| `failing_at` / `mock_step` on a class step | still retried under the class policy | US7 |
|
|
61
|
+
| `steps[:x].retry_source` | `:step_class` / `:step_block` / `:none` | US7 |
|
|
62
|
+
| `ChargeCard.run(args)` directly, failing | one attempt, `Failure` returned | FR-013 |
|
|
63
|
+
| `retries backoff: :bogus` on a class | `ArgumentError` at class definition | FR-004 |
|
|
64
|
+
|
|
65
|
+
## Demo acceptance run
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
docker compose run --rm demo-app bin/rails demo:step_retry
|
|
69
|
+
docker compose run --rm demo-app bundle exec rspec spec/reactors/step_retry_demo_reactor_spec.rb
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The rake task prints three outcomes:
|
|
73
|
+
|
|
74
|
+
1. a class step that succeeds after retries (`attempts=3 success?=true`);
|
|
75
|
+
2. a class step that exhausts its retries, with an earlier step compensated
|
|
76
|
+
(`success?=false attempts=3 compensated=true`);
|
|
77
|
+
3. a step with no declaration that is attempted once (`attempts=1`).
|
|
78
|
+
|
|
79
|
+
When running from a git worktree, pass an isolated compose project name (`-p <name>`) so
|
|
80
|
+
the fixed container names don't collide with another worktree's stack.
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# Research: Step-Scoped Retry Declarations
|
|
2
|
+
|
|
3
|
+
Every decision below was checked against the code on `retry_confs_in_steps` (base `900d6522`).
|
|
4
|
+
Nothing in Technical Context was left open.
|
|
5
|
+
|
|
6
|
+
## R1 — How `retry_defaults` works today
|
|
7
|
+
|
|
8
|
+
**Finding**:
|
|
9
|
+
|
|
10
|
+
- `Dsl::Reactor.included` sets `@retry_defaults = {max_attempts: 3, …}` on
|
|
11
|
+
`RubyReactor::Reactor` **only** (`lib/ruby_reactor/dsl/reactor.rb:14`). Nothing copies it to
|
|
12
|
+
subclasses.
|
|
13
|
+
- The reader `retry_defaults` lazily returns `{max_attempts: 1, …}` for any subclass that never
|
|
14
|
+
called it (`dsl/reactor.rb:58-68`).
|
|
15
|
+
- `StepBuilder#build`, `ComposeBuilder#build` and `AsyncReactorBuilder#build` **snapshot**
|
|
16
|
+
`@reactor.retry_defaults` into `retry_config` when their own block declared none
|
|
17
|
+
(`step_builder.rb:163`, `compose_builder.rb:74`, `async_reactor_builder.rb:52`). So a
|
|
18
|
+
`retry_defaults` line only affects steps declared *after* it. This is the "unpredictable"
|
|
19
|
+
behavior the user called out.
|
|
20
|
+
- `RetryManager#calculate_backoff_delay` falls back to `reactor_class.retry_defaults` for
|
|
21
|
+
`backoff`/`base_delay` (`executor/retry_manager.rb:29-30`).
|
|
22
|
+
- `RSpec::TestSubject` copies `@retry_defaults` into its three generated execution subclasses
|
|
23
|
+
(`rspec/test_subject.rb:559, 651, 739`).
|
|
24
|
+
|
|
25
|
+
**Consequence**: a reactor that never called `retry_defaults` already runs undeclared steps
|
|
26
|
+
exactly once. Removing the feature changes behavior only for reactors that call it (spec US1
|
|
27
|
+
scenario 3).
|
|
28
|
+
|
|
29
|
+
**Callers to migrate**: `spec/async_retry_dsl_spec.rb:23-33`, `spec/ruby_reactor_spec.rb:14, 221`,
|
|
30
|
+
`spec/support/order_processing_reactor.rb:28`, `demo_app/spec/support/order_processing_reactor.rb:28`,
|
|
31
|
+
plus docs (see R10).
|
|
32
|
+
|
|
33
|
+
## R2 — How to remove `retry_defaults`
|
|
34
|
+
|
|
35
|
+
**Decision**: replace the method with a stub that raises `Error::DeprecatedDslError` when the
|
|
36
|
+
class is defined, and delete every read of it (the builder fallbacks, the `RetryManager`
|
|
37
|
+
fallback, the `TestSubject` copies, and the `included` ivar).
|
|
38
|
+
|
|
39
|
+
**Rationale**: this is exactly how the project removed `async true` on reactors
|
|
40
|
+
(`dsl/reactor.rb:48-56`) and `async` in step/compose blocks (`step_builder.rb:119-131`). A call
|
|
41
|
+
fails loudly at load time with a migration message instead of being silently ignored. The
|
|
42
|
+
error names the reactor (`name` or `"anonymous reactor"`) and says: declare `retries` on each
|
|
43
|
+
step class or step block that needs it.
|
|
44
|
+
|
|
45
|
+
**Alternatives considered**:
|
|
46
|
+
|
|
47
|
+
- *Deprecation warning, keep working for one release*: rejected. The user asked to remove it
|
|
48
|
+
altogether, and keeping it alive also keeps the ordering bug from R1.
|
|
49
|
+
- *Delete the method outright (`NoMethodError`)*: rejected. It gives no migration hint and
|
|
50
|
+
breaks the project's established removal pattern.
|
|
51
|
+
|
|
52
|
+
**Delivery**: this is Phase A of the plan and ships first, as its own commit, with the full
|
|
53
|
+
suite green (spec FR-017).
|
|
54
|
+
|
|
55
|
+
## R3 — Where `retries` lives for a step class
|
|
56
|
+
|
|
57
|
+
**Decision**: a new module `RubyReactor::Dsl::Retryable`, modeled on `Dsl::Lockable::ClassMethods`,
|
|
58
|
+
containing:
|
|
59
|
+
|
|
60
|
+
- `retries(max_attempts: 3, backoff: :exponential, base_delay: 1)`: validates, then stores
|
|
61
|
+
`@retry_config`;
|
|
62
|
+
- `retry_config`: the reader, `nil` when nothing was declared;
|
|
63
|
+
- `inherited(subclass)`: copies `@retry_config` to the subclass, exactly like
|
|
64
|
+
`Lockable#inherited`.
|
|
65
|
+
|
|
66
|
+
`RubyReactor::Step` **extends** it (class-level DSL). `StepBuilder`, `ComposeBuilder` and
|
|
67
|
+
`AsyncReactorBuilder` **include** it, which replaces their three identical `retries` methods.
|
|
68
|
+
The same is already done with `Lockable::ClassMethods` in `StepBuilder` (`step_builder.rb:8`).
|
|
69
|
+
|
|
70
|
+
**Rationale**: the user asked us to emulate the locks design. One module gives both forms the
|
|
71
|
+
same vocabulary, the same defaults and the same validation (spec FR-001/FR-002/FR-004), and it
|
|
72
|
+
removes duplication instead of adding it. Inheritance by copying in `inherited` matches locks,
|
|
73
|
+
so a subclass redeclaring its policy leaves its parent and siblings untouched (FR-010).
|
|
74
|
+
|
|
75
|
+
**Alternatives considered**:
|
|
76
|
+
|
|
77
|
+
- *Walk `superclass` in the reader (like `input_contract`)*: works too, but it would be a
|
|
78
|
+
second inheritance mechanism next to Lockable's. Rejected for consistency.
|
|
79
|
+
- *A `RetryPolicy` value object*: rejected. There is only one consumer shape (a 3-key hash
|
|
80
|
+
read by `RetryManager`/`StepWorker`), so an object would be an abstraction with no second
|
|
81
|
+
use case (Constitution V).
|
|
82
|
+
|
|
83
|
+
## R4 — Validation of retry values
|
|
84
|
+
|
|
85
|
+
**Decision**: `Retryable#retries` raises `ArgumentError` when the declaration is made if:
|
|
86
|
+
|
|
87
|
+
- `max_attempts` is not an `Integer` `>= 1`;
|
|
88
|
+
- `backoff` is not one of `%i[exponential linear fixed]`;
|
|
89
|
+
- `base_delay` is not a `Numeric` `>= 0`.
|
|
90
|
+
|
|
91
|
+
The message names the owner (`name`: the step symbol in a builder, the class name on a step
|
|
92
|
+
class), the option and the bad value.
|
|
93
|
+
|
|
94
|
+
**Rationale**: `ArgumentError` at declaration time is what `with_period`, `with_rate_limit`
|
|
95
|
+
and `validate_rollback_wait!` already do (`dsl/lockable.rb`). An unknown backoff strategy
|
|
96
|
+
fails today only at the first retry (`RetryContext.calculate_backoff_delay` raises
|
|
97
|
+
`ArgumentError`, `retry_context.rb:94`), which can be in production, days later.
|
|
98
|
+
`ActiveSupport::Duration` (`5.seconds`) passes the `Numeric` check, because
|
|
99
|
+
`Duration#is_a?` delegates to its value, so the documented Rails idiom keeps working.
|
|
100
|
+
|
|
101
|
+
**Behavior change**: `max_attempts: 0`, which today means "no retry", is now refused and must
|
|
102
|
+
be written `max_attempts: 1` (spec Assumptions). It goes in the migration note.
|
|
103
|
+
|
|
104
|
+
## R5 — Effective policy and precedence on `StepConfig`
|
|
105
|
+
|
|
106
|
+
**Decision**: `StepConfig` stores the builder's own declaration (`nil` when none) and resolves
|
|
107
|
+
it lazily, the same way `lock_config` does (`step_builder.rb:286-304`):
|
|
108
|
+
|
|
109
|
+
```text
|
|
110
|
+
retry_config = own declaration || impl.retry_config (if impl responds) || NO_RETRIES
|
|
111
|
+
retry_source = :step_block | :step_class | :none
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
`NO_RETRIES = { max_attempts: 1, backoff: :exponential, base_delay: 1 }.freeze`.
|
|
115
|
+
`retryable?`, `RetryManager`, `StepWorker` and `StepCoordination#retry_pending?` keep reading
|
|
116
|
+
`retry_config` unchanged. Every hash now carries all three keys, so the reactor fallbacks in
|
|
117
|
+
`RetryManager` are unnecessary and removed in Phase A.
|
|
118
|
+
|
|
119
|
+
**Rationale**: resolving lazily through `impl` is what makes the class policy apply on every
|
|
120
|
+
path that already consults `step_config.retry_config`, with no per-path changes: the
|
|
121
|
+
in-process `RetryManager`, the background requeue, `StepWorker` for `async_step`, and resume
|
|
122
|
+
(FR-011/FR-012). `retry_source` covers the introspection requirement (FR-014) with one method.
|
|
123
|
+
|
|
124
|
+
**Alternatives considered**: snapshotting `impl.retry_config` at build time. Rejected: it
|
|
125
|
+
diverges from the lock readers and would miss a class policy declared after the reactor
|
|
126
|
+
references the class (for example after a reopen or reload).
|
|
127
|
+
|
|
128
|
+
## R6 — Conflict between class and step block
|
|
129
|
+
|
|
130
|
+
**Decision**: `StepBuilder#build` gains `check_retry_conflict!`, next to
|
|
131
|
+
`check_coordination_conflicts!`. It raises `Error::ValidationError` when the block declared
|
|
132
|
+
`retries` **and** `@impl.respond_to?(:retry_config) && @impl.retry_config`. The message has
|
|
133
|
+
the same shape as the lock one: `"<Reactor> step :<name> declares `retries` inline, but
|
|
134
|
+
<Class> declares it too. Keep ONE: …"`, and it also mentions subclassing as the way to vary
|
|
135
|
+
the policy per workflow.
|
|
136
|
+
|
|
137
|
+
**Rationale**: FR-009 asks for the same rule as locks. An inherited class policy counts as a
|
|
138
|
+
declaration, since `retry_config` returns the copied value.
|
|
139
|
+
|
|
140
|
+
`ComposeBuilder` and `AsyncReactorBuilder` need no check: their `impl` is an internal
|
|
141
|
+
`ComposeStep`/`AsyncReactorStep` that never declares retries.
|
|
142
|
+
|
|
143
|
+
## R7 — Direct invocation (clarified: runs once)
|
|
144
|
+
|
|
145
|
+
**Finding**: `Step.run` never enters `RetryManager`. `StepCoordination#retry_pending?` already
|
|
146
|
+
returns `false` for direct calls (`context_state?` is `!@direct && …`,
|
|
147
|
+
`step_coordination.rb:533-540, 679-681`), and the existing comment says so: "A direct call has
|
|
148
|
+
no retry policy of its own — it is never retried."
|
|
149
|
+
|
|
150
|
+
**Decision**: no runtime change. Add one spec proving that a step class declaring
|
|
151
|
+
`retries max_attempts: 3` and called directly runs once and returns its failure. Document it
|
|
152
|
+
in `retry_configuration.md` and next to the direct-call docs, contrasting it with locks
|
|
153
|
+
(FR-013).
|
|
154
|
+
|
|
155
|
+
## R8 — Test surface (`TestSubject`, matchers)
|
|
156
|
+
|
|
157
|
+
**Finding**: `mock_step` and `failing_at` replace only `@run_block` on the step config
|
|
158
|
+
(`test_subject.rb:797-826`), so `impl`, and with it the class policy, is kept. The
|
|
159
|
+
`have_retried_step` matcher (`rspec/matchers.rb:130`) reads attempt counts from the context,
|
|
160
|
+
not from the declaration.
|
|
161
|
+
|
|
162
|
+
**Decision**: no new matcher. Delete the three `@retry_defaults` copies (Phase A). Add specs
|
|
163
|
+
proving that `failing_at`/`mock_step` on a class step still retries under the class policy
|
|
164
|
+
(FR-015).
|
|
165
|
+
|
|
166
|
+
## R9 — Versioning
|
|
167
|
+
|
|
168
|
+
**Finding**: the version is `0.8.3`, managed by release-please. Earlier breaking removals
|
|
169
|
+
were released as `feat!` with a `⚠ BREAKING CHANGES` section and a **Migration:** line in
|
|
170
|
+
`CHANGELOG.md` (for example `async true`, `CHANGELOG.md:329`).
|
|
171
|
+
|
|
172
|
+
**Decision**: Phase A lands as a `feat!:` commit whose `BREAKING CHANGE:` footer carries the
|
|
173
|
+
migration text. Release-please generates the CHANGELOG entry from it. The pre-1.0 bump size
|
|
174
|
+
is release-please's call, as with earlier breaking releases. Phase B is a plain `feat:`.
|
|
175
|
+
|
|
176
|
+
## R10 — Documentation and demo impact
|
|
177
|
+
|
|
178
|
+
**`retry_defaults` appears in**:
|
|
179
|
+
|
|
180
|
+
- `documentation/retry_configuration.md` (the "Reactor-Level Defaults" section) and
|
|
181
|
+
`documentation/core_concepts.md` (≈ line 360, "Uses reactor defaults");
|
|
182
|
+
- `documentation/background_and_async.md` (≈ lines 482-530);
|
|
183
|
+
- `documentation/examples/{inventory_management,order_processing,payment_processing}.md`;
|
|
184
|
+
- the stale copies under `demo_app/documentation/` (`async_reactors.md`, the same `examples/`
|
|
185
|
+
files, `retry_configuration.md`).
|
|
186
|
+
|
|
187
|
+
**README**: the Features bullet (line 24) and the Retry Configuration blurb (line 1486,
|
|
188
|
+
"configure retries at the reactor or step level") both need rewording.
|
|
189
|
+
|
|
190
|
+
**Demo (Constitution VI)**: there is no retry-specific demo today. Retries appear only inline
|
|
191
|
+
in `signal_demo_reactor.rb` and `order_processing_reactor.rb`. Add `StepRetryDemoReactor` using
|
|
192
|
+
class steps, the `demo:step_retry` rake task, and
|
|
193
|
+
`demo_app/spec/reactors/step_retry_demo_reactor_spec.rb`, modeled on
|
|
194
|
+
`step_lock_demo_reactor.rb` and `inheritable_step_demo_reactor_spec.rb`.
|