MuleSoft Scatter Gather Pattern
The Scatter-Gather component sends the same message to multiple routes simultaneously and waits for all routes to complete before continuing. Instead of calling three external services one after another (which takes three times as long), Scatter-Gather calls all three at the same time and collects all responses. This parallel processing pattern significantly reduces response times.
The Problem It Solves
Imagine you need to show a customer's full profile that combines data from Salesforce, your internal database, and a shipping provider. Calling them sequentially takes 300ms + 200ms + 400ms = 900ms total. Scatter-Gather calls all three simultaneously. The total time equals the slowest call: 400ms. That is 55% faster.
Sequential vs Scatter-Gather Timing
Sequential Calls (900ms total):
Timeline: 0ms 300ms 500ms 900ms
|---------|---------|-------------|
Salesforce Database Shipping Done
Scatter-Gather (400ms total):
Timeline: 0ms 400ms
|------- Salesforce --------|
|---- Database -------------|
|--------- Shipping --------|
Done
All three run at the same time. Done when the slowest finishes.
Scatter-Gather Structure
Inside a Scatter-Gather component, you define two or more routes. Each route is an independent sequence of components. All routes start at the same time. Each route receives a copy of the incoming message. After all routes finish, Scatter-Gather merges the results into a single output.
Scatter-Gather in Anypoint Studio
[HTTP Listener: GET /customer/{id}/profile]
│
▼
[Set Variable: customerId = attributes.uriParams.id]
│
▼
┌─────────────────────────────────────────────────────┐
│ SCATTER-GATHER │
│ │
│ Route 1: Get CRM Data │
│ [HTTP Request: GET salesforce-sys-api/contacts │
│ /{customerId}] │
│ │
│ Route 2: Get Order History │
│ [Database: SELECT * FROM orders │
│ WHERE customer_id = #[vars.customerId]│
│ │
│ Route 3: Get Shipping Status │
│ [HTTP Request: GET shipping-sys-api/customer │
│ /{customerId}/last-shipment] │
└─────────────────────────────────────────────────────┘
│
▼ (all three routes finished)
[Transform: merge results into unified response]
Scatter-Gather Output Structure
The output of Scatter-Gather is an object where each key is a route number and the value is the message produced by that route. Route numbers start at zero. Use a Transform Message component after Scatter-Gather to combine the results into the shape you want.
Scatter-Gather Raw Output
{
"0": {
"payload": { "name": "Alice Smith", "email": "alice@email.com" },
"attributes": { ... }
},
"1": {
"payload": [ {"orderId":"O1","total":150}, {"orderId":"O2","total":89} ],
"attributes": { ... }
},
"2": {
"payload": { "lastShipDate": "2024-01-10", "carrier": "FedEx" },
"attributes": { ... }
}
}
Transform Message after Scatter-Gather:
%dw 2.0
output application/json
---
{
"name": payload."0".payload.name,
"email": payload."0".payload.email,
"orders": payload."1".payload,
"lastShipDate": payload."2".payload.lastShipDate,
"carrier": payload."2".payload.carrier
}
Error Handling in Scatter-Gather
By default, if any route fails, Scatter-Gather fails the entire component and the error handler of the parent flow runs. This is usually the right behavior — if one data source is unavailable, the complete response cannot be assembled.
For cases where you want to continue even if some routes fail, wrap each route's logic in an error handler that catches errors and returns a default value instead of propagating.
Scatter-Gather with Per-Route Error Handling
SCATTER-GATHER:
Route 1: Get CRM Data (critical — must succeed)
[HTTP Request: salesforce-sys-api/contacts/{id}]
(no error handler — let it fail)
Route 2: Get Order History (non-critical — use empty if fails)
[Database: SELECT orders...]
Error Handler:
On Error Continue: ANY
[Set Payload: []] ← return empty array on failure
Route 3: Get Shipping Status (non-critical — use null if fails)
[HTTP Request: shipping-sys-api/last-shipment]
Error Handler:
On Error Continue: ANY
[Set Payload: null] ← return null on failure
Scatter-Gather Timeout
Set a timeout on the Scatter-Gather component to prevent it from waiting forever if one route hangs. If the timeout expires before all routes finish, Scatter-Gather raises a timeout error that your error handler can catch.
Scatter-Gather Configuration:
Timeout: 5000 ms (5 seconds)
If shipping API takes 8 seconds:
At 5 seconds → Scatter-Gather raises MULE:TIMEOUT
Error Handler:
[Set Payload: {"error": "Profile data unavailable — timeout"}]
[HTTP status: 504]
Scatter-Gather for Parallel Writes
Scatter-Gather is not only for reading from multiple sources. Use it to write the same data to multiple destinations simultaneously. When a new customer registers, write to the CRM, the marketing system, and the billing system all at once.
Parallel Write Pattern
[HTTP Listener: POST /customers]
│
▼
[Transform: validate and standardize]
│
▼
SCATTER-GATHER (write to all three in parallel):
Route 1: [Salesforce: Create Contact]
Route 2: [Database: INSERT INTO crm_customers...]
Route 3: [HTTP Request: POST to marketing-platform/subscribers]
│
▼
[Transform: confirm all writes succeeded]
│
▼
[HTTP Response: 201 Created]
When Not to Use Scatter-Gather
Scatter-Gather is not the right tool when later routes depend on the results of earlier routes. If you need to look up a customer ID first and then use that ID to query orders, use sequential steps — not Scatter-Gather. Use Scatter-Gather only when all routes are independent of each other and can run with the same input data.
