Jenkins / Evidence, reuse, and authority / Lesson 10
Parallel branches and matrix evidence
Expand intentional combinations while keeping files, results, and failure propagation unambiguous.
On this page
Lesson goals
- Distinguish possible parallelism from available executor capacity.
- Review per-branch isolation and required matrix coverage.
Parallelism follows dependency structure
Parallel stages can reduce elapsed feedback when their work is independent and sufficient capacity exists. Parcel’s plain and unicode format checks can operate on the same immutable source without depending on each other. That does not mean they should write the same report path or mutate a shared dependency directory concurrently. Draw what each branch reads and writes before adding parallel. The scheduler may still serialize or queue work under agent, executor, resource, or plugin constraints. A parallel declaration expresses eligible structure, not a promise of simultaneous execution.
Read the branch result contract
The stage fragment below names two independent illustrative branches and enables fail-fast behavior. Each echo prints only a label, so this is not an application test. Real branches need assertions and uniquely identified evidence. failFast can interrupt siblings after failure under documented behavior, which saves work but may reduce comparative diagnostic data. Decide whether early cancellation or complete branch results matter more for the check. Cancellation is not a successful required outcome, and interrupted external side effects need separate recovery reasoning.
stage("Format checks") {
failFast true
parallel {
stage("Plain") { steps { echo "plain fixture" } }
stage("Unicode") { steps { echo "unicode fixture" } }
}
}
The enclosing Pipeline and appropriate agent allocation are omitted. No branches run and no application assertions are supplied. The fragment demonstrates structure, not a verified Jenkins timing result.
A matrix multiplies risk coverage and cost
Declarative matrix can generate combinations from axes such as platform and fixture mode, with exclusions for unsupported combinations. Tie each axis to a real supported contract rather than multiplying dimensions mechanically. Three platforms and two modes start with six cells before filtering. Exclusions should explain a deliberate scope choice, not quietly remove a failing supported case. Matrix syntax and nested-stage restrictions require the installed Declarative plugin’s supported behavior. Review the expanded required set and stable cell identities before deciding how a summary gates release.
Count combinations and explicit exclusions
The complete local model below expands two platforms and two fixture modes, then excludes one declared unsupported pair. The exclusion is a teaching assumption, not a Jenkins or operating-system limitation. The program does not parse Declarative matrix syntax or model agent allocation. It makes the expected set visible so reviewers can ask whether a missing cell is intentional, skipped, aborted, or failed. A downstream aggregator should compare observed evidence against that declared set instead of accepting whichever branches happened to publish last.
from itertools import product
all_cells = set(product(["linux", "windows"], ["plain", "unicode"]))
excluded = {("windows", "unicode")}
required = all_cells - excluded
print(len(all_cells))
print(sorted(required))
4
[('linux', 'plain'), ('linux', 'unicode'), ('windows', 'plain')]
Only in-memory combinations are calculated. Real Pipeline syntax, plugin support, result names, and platform compatibility are not tested.
Isolate mutable files and aggregate deliberately
Branches sharing one allocated workspace can collide even when their stage names differ. Use deliberate per-branch directories or isolated allocations and explicit artifact transfer where needed. Give report and stash names unique identities. Avoid shared mutable Groovy collections as an informal result database across branches; orchestration persistence and concurrent updates add complexity. Retain individual outcomes and define how missing or aborted required cells affect promotion. If more parallelism increases queueing or setup overhead, measure those phases before assuming another executor or larger matrix will improve end-to-end feedback.
Common errors and fixes
Parallel branches write the same report file.
- Why it happens
- Presentation names were mistaken for filesystem isolation.
- How to fix it
- Separate writable paths and aggregate identified outputs afterward.
- Prevent it next time
- Review per-branch reads, writes, stash names, and reports.
A fail-fast canceled cell is counted as passed.
- Why it happens
- Absence of a red assertion was confused with successful required evidence.
- How to fix it
- Require explicit acceptable results for the declared cell set.
- Prevent it next time
- Test failure, cancellation, and missing-cell summary behavior.
A larger matrix increases total delay unexpectedly.
- Why it happens
- Executor capacity, setup, and transfer overhead were ignored.
- How to fix it
- Measure queue and execution and choose risk-relevant dimensions.
- Prevent it next time
- Compare expanded coverage and elapsed feedback together.
Check your understanding
1. Two branches use the same top-level agent. Are their output directories automatically separate?
Show worked solution
No. Stage structure alone does not isolate files in a shared workspace. Choose explicit directories or allocations and collision-free output names. Review any shared mutable dependency or cache directory separately.
2. A supported platform repeatedly fails. Is excluding its matrix cell a valid performance optimization?
Show worked solution
Not without a reviewed support and risk decision. Exclusion changes the coverage contract rather than simply speeding the same check. Fix the defect or explicitly revise supported scope and communicate that decision through the release policy.
Key takeaways
- Parallel structure does not guarantee capacity or file isolation.
- Compare observed cells with an explicit required evidence set.