Skip to main content

Two concurrency semantics

<Parallel> supports two independent caps that may coexist:
  • maxConcurrency (leaf-task cap). Caps the tasks whose innermost enclosing group is this parallel. A nested <Parallel> starts its own group, so its tasks do not count against the outer cap. Use it when the children are flat tasks (like the checks example above).
  • subtreeConcurrency (subtree cap, opt-in, int >= 1). Caps how many direct children of this parallel are in flight at once, where every descendant task counts toward the child it descends from. A child is in flight from its first started task until all of its tasks finish; when a child finishes, the freed slot admits the next child in document order. An in-flight child may always finish its remaining tasks (even the ones in nested parallels) while over-cap siblings wait.
The difference matters as soon as children are subtrees. In a kanban-shaped workflow, tickets fanned out in parallel with each ticket a sequence of implement then reviews, maxConcurrency={4} neither means “4 tickets” (each ticket’s first task belongs to the outer group, but the nested review parallel escapes it) nor bounds reviews. subtreeConcurrency={4} means exactly “4 tickets in flight”:
Here at most 2 tickets are worked at once; within an active ticket at most 3 reviews run concurrently; the run-level cap still bounds total in-flight tasks.

Subtree cap notes

  • Descendant tasks record their nearest ancestor <Parallel subtreeConcurrency>: nesting a second subtree-capped parallel inside a child re-scopes its descendants to the inner group.
  • Child identity is the direct child’s explicit key/id prop when the element carries one through (e.g. <Task id>, <Parallel id>, <Worktree id>), otherwise its child ordinal. Keep direct-child order stable (or give ids) so resumed runs re-admit the same children.
  • Admission is deterministic in document order and derived purely from task states, so a resumed run makes the same decisions from a restored state map.

Notes

  • Group completes when all children finish. To let the group proceed past a failing child, set continueOnFail on that individual child <Task>. It is not a <Parallel> prop.
  • Children receive parallelGroupId and parallelMaxConcurrency in their descriptor; under a subtree cap every descendant task also receives subtreeGroupId, subtreeChildKey, and subtreeMax.
  • The run-wide cap applies on top of every group. With no --max-concurrency pin, it starts at 4 and automatically grows with queued demand up to SMITHERS_AUTO_MAX_CONCURRENCY_CEILING (16 by default). A declared maxConcurrency or subtreeConcurrency width can also raise the initial run-wide cap above that automatic ceiling. --max-concurrency N pins the cap instead: it disables those raises and the run never exceeds N, but N itself may be larger than the automatic ceiling. subtreeConcurrency composes the same way: leaf-group cap, subtree cap, and the run-wide cap must all pass.