Stop Waiting on APIs: Run Them in Parallel with MuleSoft Scatter-Gather

Sequential API calls are slowing your MuleSoft flows. Learn the Scatter-Gather pattern through two hands-on flows aggregation and fault tolerance with importable code

Introduction

In most integrations, you eventually hit a moment where one request needs data from several places at once — a user's profile from one API, their orders from another, their preferences from a third. The naive approach calls each one in sequence, so the total wait is the sum of every call. The Scatter-Gather router fixes this: it fans a single request out to multiple routes, runs them in parallel, and gathers the responses back into one Mule event. Total time becomes roughly the slowest route, not the sum of all of them.

This post teaches Scatter-Gather through just two flows. The first covers everything you do when routes succeed — parallel fan-out, controlling concurrency, and capturing the aggregated result. The second covers everything that happens when routes fail — errors and timeouts, and how Scatter-Gather lets you recover the routes that did work. Both flows call real public APIs, so you can deploy the companion file, hit each endpoint, and see live data.


Flow 1 — The Happy Path: Fan Out, Control Concurrency, Aggregate

Endpoint: GET /aggregate

This single flow shows the full success story of Scatter-Gather. One incoming request fans out to three different APIs at once. Three things are worth understanding here, and they all live in one component.

Parallel fan-out. The three HTTP calls run concurrently, so the flow finishes in about the time of the slowest call rather than the sum of all three. This is the entire reason Scatter-Gather exists.

Controlling concurrency with maxConcurrency. By default every route runs in parallel. Setting maxConcurrency="2" caps it so at most two routes run at the same time — useful when a downstream system can't absorb unlimited concurrent load. (Set it to 1 and the routes run fully sequentially.)

Capturing the result with target. Scatter-Gather normally replaces the payload with its result map. Using target="mcAggregatedData" sends that map to a variable instead, leaving the original payload untouched — the response proves this by echoing the original payload back alongside the combined data.

Finally, a DataWeave transform reshapes the raw {0, 1, 2} index-keyed map into one tidy JSON object by reading each route out by its index.

Parallel API calls with Scatter-Gather flow
Target variable and Max Concurrency settings
Three routes combined into one response

Flow 2 — Failure Handling: One Error for Everything That Breaks

Endpoint: GET /resilient

Real APIs fail and stall, so this flow shows what Scatter-Gather does under pressure. It deliberately wires up three routes that behave differently: one fails fast with a 404, one is slow and trips the timeout, and one succeeds.

Timeouts. Setting timeout="2000" means any route that hasn't finished in two seconds throws MULE:TIMEOUT. The slow route here sleeps three seconds on purpose, so it always trips.

One combined error. This is the key idea. No matter how many routes fail or how they fail, Scatter-Gather throws a single MULE:COMPOSITE_ROUTING error and the flow branches to one error handler. That error object carries both the failures and the results from routes that succeeded — so a broken route never throws away the good work.

Recovering the survivors. Inside the handler, failures and results are both keyed by route index, and a given index appears in exactly one of them. The transform walks both maps to build a clear report: which routes failed and why, and the data from the route that came back clean.

Fault-tolerant Scatter-Gather with COMPOSITE_ROUTING handler
Failed routes reported, successful route recovered

Conclusion

Two flows cover the whole picture. Flow 1 is why you reach for Scatter-Gather: parallel calls, with maxConcurrency and target to control how it runs and where the result lands. Flow 2 is why you can trust it in production: every failure — including timeouts — folds into one COMPOSITE_ROUTING error that still hands you the routes that succeeded.

Two rules that cause startup failures if ignored: a Scatter-Gather needs at least two routes, and it only works with repeatable streams (Mule's default — nonrepeatable streams are read once and lost).

Mulecraft Footer