skip to content

How do reactor failure behavior (-ff/-fae/-fn) and parallel builds (-T) interact with reactor ordering?

level: principalimportance: nice to knowfreq 25%

answer

  1. -ff default stop-first
  2. -fae continue + report all, skip dependents
  3. -fn never fail
  4. -T 1C = thread per core
  5. parallel still honors DAG; chains serialize

basics

~20 s

Failure flags decide what happens after a module fails: -ff (fail-fast, default) stops immediately, -fae (fail-at-end) keeps building independent modules then reports all failures, -fn (fail-never) ignores failures. -T runs independent modules in parallel threads while still honoring dependency order.

solid answer

~40 s

Reactor ordering defines a dependency DAG; the failure and parallelism flags operate on top of it. `-ff` (fail-fast, the default) aborts the whole reactor on the first module failure. `-fae` (fail-at-end) skips only the failed module's downstream dependents but continues building modules unrelated to the failure, then summarizes every failure at the end — useful in CI to see all broken modules in one run. `-fn` (fail-never) reports failures but never stops, returning success-ish. Parallel builds with `-T` (e.g. `-T 4` or `-T 1C` = 1 thread per core) build modules concurrently, but the scheduler still respects the topological order: a module starts only once all its dependencies have finished. Independent branches of the graph run in parallel, so wide, shallow graphs parallelize best; a long dependency chain serializes regardless of thread count.

code

bash · 2 lines
bash
# Parallel, fail-at-end, full verify (good for CI):
mvn -T 1C --fail-at-end verify

go deeper

for a junior

Knows the build stops on first failure by default.

for a middle

Can name -fae and -T and what they roughly do.

for a senior

Chooses -fae for CI visibility and uses -T while watching for non-thread-safe plugins.

for a principal

Shapes module graphs for parallelism, standardizes CI flags (-T 1C --fail-at-end), and audits plugins for thread safety.

## Layering: ordering first, then policy Reactor ordering produces a dependency DAG. The failure-handling and parallelism flags are policies applied to that DAG — they never violate the rule that a dependency builds before its dependents. ## Failure modes (`--fail-*`) - **`-ff` / `--fail-fast`** (default): stop the entire reactor at the first module that fails. Fastest feedback for local dev. - **`-fae` / `--fail-at-end`**: when a module fails, Maven skips that module's **downstream dependents** (they can't be built correctly) but keeps building modules **not affected** by the failure. At the end it prints a consolidated list of all failures. Great in CI: one run surfaces every independently-broken module instead of fixing-and-rerunning repeatedly. - **`-fn` / `--fail-never`**: never stop and never fail the overall build due to a module failure; failures are logged. Useful for "build as much as possible and just collect results" scenarios. ## Parallel builds (`-T`) `-T` enables multi-threaded module building: - `-T 4` — 4 threads. - `-T 1C` — 1 thread per available CPU core (`2C` = two per core, etc.). The parallel scheduler walks the DAG: a module is eligible to start only when **all of its dependencies have completed**. So: - **Independent branches build at the same time.** - A **linear chain** (a → b → c) can't be parallelized and runs serially no matter how many threads you allow. - Wide, shallow graphs see the biggest speedups. ## Practical gotchas - Plugins must be **thread-safe** for `-T` to be safe; non-thread-safe plugins can produce warnings or flaky output. - Parallel build logs interleave; use the reactor summary to read results. - `-fae` plus `-T` is a common CI combo: maximize work done and report all failures. ## Example ```bash # CI: use all cores, build everything possible, report all failures mvn -T 1C --fail-at-end verify # Local quick feedback (defaults): stop on first failure, single-threaded mvn verify ```

  • Why might -T give little speedup on some projects?
    If the module graph is a long dependency chain, each module waits for the previous one, so there's nothing to parallelize. Wide, independent branches parallelize; deep chains don't.
  • With -fae, what happens to modules downstream of a failed module?
    They are skipped (they depend on broken output), but unrelated modules keep building, and all failures are reported together at the end.

saying these in an interview costs you the question

  • Saying -T can build a module before its dependencies finish
  • Confusing -fae (skips only dependents) with -fn (ignores all failures)
  • Assuming all plugins are thread-safe under -T

context