Class: Restate::CombinedFuture
- Inherits:
-
Object
- Object
- Restate::CombinedFuture
- Defined in:
- lib/restate/durable_future.rb,
sig/restate.rbs
Overview
A lazy combinator over one or more child futures. The child set can mix
DurableFuture leaves (with raw handles) and nested CombinedFuture nodes.
The shared-core uses the tree shape to make suspension decisions; nothing
blocks until .await is called, so combinators are composable:
Restate.race(Restate.all(a, b), c).await
Supported variants (mirroring UnresolvedFuture in restate-sdk-shared-core):
:first_completed → JS Promise.race
:all_succeeded_or_first_failed → JS Promise.all
:first_succeeded_or_all_failed → JS Promise.any
:all_completed → JS Promise.allSettled
Constant Summary collapse
- VALID_VARIANTS =
%i[ first_completed all_succeeded_or_first_failed first_succeeded_or_all_failed all_completed ].freeze
Instance Method Summary collapse
-
#await ⇒ Object
Block until this combinator settles per its variant.
-
#completed? ⇒ Boolean
Non-blocking introspection.
- #finalize_all_completed ⇒ Array[Hash[Symbol, untyped]]
- #finalize_all_succeeded ⇒ Array[untyped]
- #finalize_first_completed ⇒ Object
- #finalize_first_succeeded ⇒ Object
- #finalize_value ⇒ Object
-
#initialize(ctx, variant, children) ⇒ CombinedFuture
constructor
A new instance of CombinedFuture.
- #resolve_combined! ⇒ void
-
#tree ⇒ Object
Recursive tree representation the native
do_awaitbinding consumes.
Constructor Details
#initialize(ctx, variant, children) ⇒ CombinedFuture
Returns a new instance of CombinedFuture.
138 139 140 141 142 143 144 145 146 147 |
# File 'lib/restate/durable_future.rb', line 138 def initialize(ctx, variant, children) raise ArgumentError, "unknown combinator variant: #{variant}" unless VALID_VARIANTS.include?(variant) @ctx = ctx @variant = variant @children = children @resolved = false @value = nil @error = nil end |
Instance Method Details
#await ⇒ Object
Block until this combinator settles per its variant. Caches results (including failures) across calls.
157 158 159 160 161 162 |
# File 'lib/restate/durable_future.rb', line 157 def await resolve_combined! unless @resolved raise @error if @error @value end |
#completed? ⇒ Boolean
Non-blocking introspection. True iff calling .await is guaranteed not to
block. Conservative for the variants that allow early-completion on failure
(+:all_succeeded_or_first_failed+, :first_succeeded_or_all_failed) — we
report false until every child is settled, because checking failure status
of a leaf would require consuming its notification.
169 170 171 172 173 174 175 176 177 178 |
# File 'lib/restate/durable_future.rb', line 169 def completed? return true if @resolved case @variant when :first_completed @children.any?(&:completed?) else @children.all?(&:completed?) end end |
#finalize_all_completed ⇒ Array[Hash[Symbol, untyped]]
212 213 214 215 216 217 218 |
# File 'lib/restate/durable_future.rb', line 212 def finalize_all_completed @children.map do |c| { status: :fulfilled, value: c.await } rescue TerminalError => e { status: :rejected, reason: e } end end |
#finalize_all_succeeded ⇒ Array[untyped]
204 205 206 207 208 209 210 |
# File 'lib/restate/durable_future.rb', line 204 def finalize_all_succeeded # Surface any settled-and-failed child first (short-circuit). After this # scan, if no failure was raised, every child must be settled-and-success # per AllSucceededOrFirstFailed semantics. @children.each { |c| c.await if c.completed? } @children.map(&:await) end |
#finalize_first_completed ⇒ Object
200 201 202 |
# File 'lib/restate/durable_future.rb', line 200 def finalize_first_completed @children.find(&:completed?).await end |
#finalize_first_succeeded ⇒ Object
220 221 222 223 224 225 226 227 228 229 230 231 |
# File 'lib/restate/durable_future.rb', line 220 def finalize_first_succeeded errors = [] # : Array[TerminalError] @children.each do |c| next unless c.completed? return c.await rescue TerminalError => e errors << e end raise TerminalError.new("all futures failed: #{errors.map(&:message).join('; ')}", status_code: 500) end |
#finalize_value ⇒ Object
191 192 193 194 195 196 197 198 |
# File 'lib/restate/durable_future.rb', line 191 def finalize_value case @variant when :first_completed then finalize_first_completed when :all_succeeded_or_first_failed then finalize_all_succeeded when :all_completed then finalize_all_completed when :first_succeeded_or_all_failed then finalize_first_succeeded end end |
#resolve_combined! ⇒ void
This method returns an undefined value.
182 183 184 185 186 187 188 189 |
# File 'lib/restate/durable_future.rb', line 182 def resolve_combined! @ctx.wait_combined(tree) @value = finalize_value rescue TerminalError => e @error = e ensure @resolved = true end |
#tree ⇒ Object
Recursive tree representation the native do_await binding consumes.
Leaves are integer handles; inner nodes are [variant, [child...]] pairs.
151 152 153 |
# File 'lib/restate/durable_future.rb', line 151 def tree [@variant, @children.map { |c| c.is_a?(CombinedFuture) ? c.tree : c.handle }] end |