Repository navigation
Conversation
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add
ctx.waitForAny(). It wakes a task on whichever comes first: one of several events or a timeout. Fabrial needs it to race an approval decision against a thread reply and a timer. It builds on thectx.subscribe()machinery from #74 rather than adding a parallel mechanism.Semantics
ctx.subscribe()handle (race-safe for events caused by earlier steps) or an inline{ event, filter }, subscribed at the call under<stepKey>::<branch>.waitForAny()call and resolves to{ key: "timeout" }rather than throwing.timeoutis rejected as a branch key at the type level.{ status: "closed" }, soctx.subscribe()on a resume is a no-op, and callingwait()on a closed handle throws.Implementation
race_step_key. New_private_register_event_racelocks the execution and returns a cached winner if there is one. Otherwise it registers inline branches through_private_register_event_wait, picks a buffered winner, or tags the branches and suspends. Settling (buffered winner or timeout) writes the race step, closes the branch keys and deletes the branch subscriptions.race_step_keyeven whenwaitForAnytagged the subscription after the dispatch statement's snapshot, and it wakes an execution suspended at the race key. The winner is chosen in the registration call on resume, with the execution locked, which is what makes "exactly one winner" hold under concurrent dispatches. Dispatch cannot do this itself because it cannot see inline subscriptions created after its snapshot._private_register_event_waitwithoutp_suspendnow leaves an existing subscription untouched. Before, a resumedsubscribe()would settle a branch subscription as timed out on its own.waithandle vs{ event }), so an{ execution }branch for ctx.start can be added later.Verification
New integration tests in
wait-for-event.test.ts:wait()throwswaitForAny()and resolves to{ key: "timeout" }waitForAnycommitted still wakes the execution. It fails if the race key is read from the statement snapshot.Type tests cover the result union, filter checking on inline branches and the reserved
timeoutkey.just lint,just format,bun run typecheckand the fullbun test(396 pass) are green. Docs:api/task-context.md(ctx.waitForAny()) andcrafting-tasks/triggers.md.Follow-ups
{ execution: id }branch together with ctx.start.{ key: "timeout" }, even without a timeout option.