Run parallel branches and safe races
Reserve shared budgets, persist branch progress, join deterministically, fail fast, and race only side-effect-safe work.
Parallel contract
Parallel workflow execution is a governed fan-out/fan-in node, not a collection
of detached futures. Every uniquely named ParallelBranch receives the same
canonical input, an attenuated Capability Set, a reserved budget share, and a
child Run.
All branches must be admitted before any starts. Joined output is keyed by stable Step identity, so completion timing never changes output order.
Budget reservations
Atomic counters alone let the fastest branch spend the whole remaining budget. Batch reservation assigns deterministic maximum ownership to every sibling. The batch is all-or-nothing; a scoped tracker cannot consume another branch's share.
Consumption becomes committed Run usage. Dropping the final scoped reservation releases unused capacity. Choose reservations as tolerated maximums, not optimistic averages.
Durable branch state
Checkpoint state records every branch as in-flight, completed with output, or failed. Successful outputs persist independently. Recovery never reruns a completed branch; incomplete work requires explicit retry authority.
Fail-fast parallelism records the failing branch and cancels unfinished siblings. Cancellation is cooperative and does not prove a remote call stopped or undo an Effect.
First-success race
A Race returns the first successful canonical output, but accepts only Pure and ReadOnly capabilities. Idempotent writes are still rejected: idempotency avoids duplicate writes, not unwanted writes from losing branches.
Every branch is polled once before a winner can be accepted. Losers are cancelled and their unused reservations are conservatively forfeited because remote usage may continue without a terminal event.
Choose a policy
Use parallel fan-out when every result is required. Use Race for redundant read-only routes where latency matters and worst-case losing cost is acceptable. Use sequential fallback when a first route can fail safely before the next begins. Avoid concurrency when external writes need deterministic ordering.
Document branch authority, reservation, failure policy, checkpoint behavior, and reconciliation before production.
Build a bounded parallel node
let per_branch = Usage { turns: 1, ..Usage::default() };
let workflow = Workflow::builder("parallel-analysis")
.parallel("analyze", [
ParallelBranch::step(
"risk", RiskStep, CapabilitySet::new(), per_branch,
),
ParallelBranch::step(
"value", ValueStep, CapabilitySet::new(), per_branch,
),
])
.build()?;
let run = RunContext::root(
BudgetTracker::new(Budget { turns: Some(2), ..Budget::default() }),
CapabilitySet::new(),
);
let outcome = workflow.run("proposal", &run).await?;The joined JSON object is keyed by stable branch ID, independent of completion
order. The parent budget must admit every reservation before any branch starts.
For race(...), use the same shape but grant only Pure or ReadOnly capabilities;
the builder rejects write-capable branches.