Two concurrency semantics
<Parallel> has two independent caps; they may coexist:
maxConcurrency(leaf-task cap). Caps tasks in this parallel’s innermost group; a nested<Parallel>opens its own group, exempting its tasks from the outer cap. Use for flat children, as in the checks example above.subtreeConcurrency(subtree cap, opt-in, int >= 1). Caps direct children in flight at once; each descendant task counts toward its child. A child is in flight from its first task to its last; a freed slot admits the next child in document order, and an in-flight child always finishes (even nested tasks) while over-cap siblings wait. If that child launches a lifecycle-linked workflow, tasks in the child and deeper descendants also draw from this budget; dynamic child-run fan-out therefore stays bounded by the declaring ancestor.
maxConcurrency={4} bounds
neither tickets (a ticket’s first task sits in the outer group; its nested
review parallel escapes it) nor reviews. subtreeConcurrency={4} means
exactly 4 tickets in flight:
Subtree cap notes
- Descendant tasks track their nearest
<Parallel subtreeConcurrency>ancestor; nesting a second subtree-capped parallel re-scopes its descendants to the inner group. - Child identity is the child’s explicit
key/idwhen present (<Task id>,<Parallel id>,<Worktree id>), else its ordinal. Keep child order stable (or add ids) so resumed runs re-admit the same children. - Admission is deterministic, derived from task state in document order, so a resumed run repeats the same decisions from its restored state.
Notes
- A group completes when all children finish.
continueOnFailon a failing child<Task>(not a<Parallel>prop) lets the group proceed past it. - Children carry
parallelGroupId/parallelMaxConcurrencyin their descriptor; under a subtree cap, descendants also getsubtreeGroupId,subtreeChildKey, andsubtreeMax. - The run-wide cap layers on top of every group cap. Unpinned, it starts at 4 and grows with demand up to
SMITHERS_AUTO_MAX_CONCURRENCY_CEILING(default 16); a declaredmaxConcurrency/subtreeConcurrencycan raise that starting point above the ceiling.--max-concurrency Npins the cap instead, disabling those raises and holding the run atNeven above the ceiling. Leaf cap, subtree cap, and run-wide cap must all pass. - Lifecycle-linked
<Subflow>children inherit every ancestor run/subtree admission scope. The awaiting parent task releases its scopes before the child starts and reacquires them after it settles, so inheritance cannot deadlock at--max-concurrency 1. A directrunWorkflowcall with onlyparentRunIdrecords detached lineage and does not inherit.