Study guide

9.2 Scatter-Gather Router: Parallel Execution, Aggregation & Error Traps

Salesforce Certified MuleSoft Developer I Exam

Track your progress as you read

Finished sections get a check mark.

1 Chapter 1: Creating Application Networks & API-Led Connectivity

1.1 The IT Delivery Gap & API-Led Connectivity Architecture 1.2 Application Network Foundations & Center for Enablement (C4E) 1.3 Anypoint Platform Architecture & Core Components

2 Chapter 2: Designing APIs with RAML & API Designer

2.1 RAML 1.0 Fundamentals, Data Types & Resource Hierarchy 2.2 Reusable API Fragments, ResourceTypes & Traits 2.3 API Mocking Service, Documentation & Anypoint Exchange Publishing

3 Chapter 3: Accessing and Modifying Mule Events

3.1 Mule 4 Event Architecture: Message, Payload, Attributes & Variables 3.2 Flow Variable Management & Target Variables Pattern 3.3 Accessing Event Metadata, Inbound Attributes & Context Properties

4 Chapter 4: Structuring Mule Applications

4.1 Modular Flow Composition: Flows, Subflows & Private Flows 4.2 Configuration Property Files & Environment Management 4.3 Secure Properties Tool, Encryption & Maven Project Packaging

5 Chapter 5: Building API Implementation Interfaces

5.1 APIkit Scaffolding, Router Configuration & Interface Generation 5.2 HTTP Listener Configuration, Path Matching & Query/URI Parameters 5.3 Interface vs. Implementation Separation & Backend Flow Wiring

6 Chapter 6: Using Connectors & External Systems

6.1 Database Connector: Select, Insert, Update, Stored Procedures & Watermarking 6.2 HTTP Request Connector: Headers, Query Params, Response Timeouts & Target Variables 6.3 Salesforce Connector, JMS Messaging & File/FTP Connectors

7 Chapter 7: Processing Records & Batch Integration

7.1 For Each Scope: Payload Iteration, Batch Size & Streaming Data 7.2 Batch Job Architecture: Input, Process, and Complete Phases 7.3 Batch Step Accept Expression, Failure Handling & Batch Aggregator 7.4 Object Store: Persisting Data Between Flow Executions

8 Chapter 8: Transforming Data with DataWeave 2.0

8.1 DataWeave 2.0 Syntax, Type System & Selectors 8.2 Core Functions: map, filter, pluck, reduce, groupBy & orderBy 8.3 Custom Functions, Format Transformations & Type Coercion 8.4 Calling Mule Flows from DataWeave & Reusing DataWeave Modules

9 Chapter 9: Routing Events & Flow Control

9.1 Choice Router: Conditional Expressions & Default Routing 9.2 Scatter-Gather Router: Parallel Execution, Aggregation & Error Traps 9.3 Async Scope, Round Robin & First Successful Routing 9.4 Validating Mule Events with the Validation Module

10 Chapter 10: Handling Errors & Exception Management

10.1 Mule 4 Error Object Hierarchy & Custom Error Types 10.2 On-Error Continue vs. On-Error Propagate Mechanisms 10.3 Try Scope Exception Isolation & Global Error Handling Strategies

11 Chapter 11: Debugging and Troubleshooting Mule Applications

11.1 Logger Configuration, Categories & Thread/Context Diagnostics 11.2 Anypoint Studio Debugger: Breakpoints, Expression Watches & Step-Through 11.3 MUnit 2.x Testing: Unit Tests, Mocking Connectors & Assertions

12 Chapter 12: Deploying and Managing APIs and Integrations

12.1 CloudHub 1.0 & 2.0 Architecture: Workers, vCores & Clustering 12.2 Runtime Manager: Application Management, Alerts, Insights & Logs 12.3 API Manager: Auto-Discovery, API Gateway, SLA Tiers & Standard Policies

9.2 Scatter-Gather Router: Parallel Execution, Aggregation & Error Traps

Key Takeaways Explain This Topic AI

The Scatter-Gather router (<scatter-gather>) broadcasts an identical clone of the incoming Mule event to two or more parallel processing routes simultaneously on separate threads.

Each parallel route executes in complete isolation; modifications made to the payload or variables in one route are invisible to other routes during execution.

Upon successful completion of all routes, Scatter-Gather aggregates the results into a composite Mule event where payload is a Map keyed by route index string ("0", "1", "2", ...), with each entry containing the respective route's MuleMessage (payload and attributes).

Variables created or modified in individual routes are merged back into the main flow context upon completion; if multiple routes modify the same variable name, the resulting value is non-deterministic.

If an unhandled error occurs in ANY route, Scatter-Gather immediately halts normal aggregation and raises a MULE:COMPOSITE_ROUTING error containing an error.childErrors collection of all failures and partial successes.

Last updated: August 2026

Scatter-Gather Router: Parallel Execution, Aggregation & Error Traps

Aggregating information from multiple disparate backends—such as querying airline, hotel, and car rental services simultaneously—is a foundational integration requirement. In Mule 4, the Scatter-Gather Router ( <scatter-gather> ) enables concurrent, parallel processing across multiple routes, aggregating individual responses into a single composite Mule message. Understanding thread dispatching, event cloning, result aggregation, variable merging, and composite error handling is essential for mastering flow control in Mule applications.

1. Scatter-Gather Execution Architecture & Event Cloning

When a Mule event enters a <scatter-gather> router, the runtime performs the following sequence:

Event Cloning: A separate, deep copy of the incoming Mule event (including payload , attributes , and vars ) is created for every declared <route> .

Parallel Dispatch: Each route is assigned to an independent thread from the Mule runtime reactive thread pool and executed concurrently.

Thread Synchronization: The router waits for all parallel routes to complete (or for a timeout or unhandled exception to occur) before proceeding. +-------------------------------------------------------------------------------------------------+

  • | SCATTER-GATHER PARALLEL ARCHITECTURE |
  • | |
  • | [ Incoming Mule Event ] |
  • | payload: { "tripId": "T-101" } |
  • | vars: { "userId": "U-88" } |
  • | | |
  • | v |
  • | +-----------------------------------+ |
  • | | <scatter-gather> Router | |
  • | +-----------------------------------+ |
  • | / | \ |
  • | [Clone Event Copy 0] [Clone Event Copy 1] [Clone Event Copy 2] |
  • | | | | |
  • | v v v |
  • | +---------------------+ +---------------------+ +---------------------+ |
  • | | Route 0 (Thread A) | | Route 1 (Thread B) | | Route 2 (Thread C) | |
  • | | <http:request> | | <http:request> | | <http:request> | |
  • | | Flight Partner API | | Hotel Partner API | | Car Rental API | |
  • | +---------------------+ +---------------------+ +---------------------+ |
  • | | | | |
  • | v v v |
  • | [Flight Message] [Hotel Message] [Car Rental Msg] |
  • | \ | / |
  • | \ | / |
  • | v v v |
  • | +-----------------------------------+ |
  • | | AGGREGATION ENGINE | |
  • | +-----------------------------------+ |
  • | | |
  • | v |
  • | [ Composite Mule Event ] |
  • | payload: { |
  • | "0": { attributes: { statusCode: 200 }, payload: { flights: [...] } }, |
  • | "1": { attributes: { statusCode: 200 }, payload: { hotels: [...] } }, |
  • | "2": { attributes: { statusCode: 200 }, payload: { cars: [...] } } |
  • | } |
  • | vars: { userId: "U-88", (merged variables from all routes) } |
  • +-------------------------------------------------------------------------------------------------+

XML Configuration Example: <flow name="aggregate-travel-itinerary-flow" doc:name="Aggregate Travel Itinerary Flow">

<http:listener config-ref="HTTP_Listener_config" path="/itinerary" doc:name="Listener"/>

<set-variable variableName="bookingId" value="#[payload.bookingId]" doc:name="Set Booking ID"/>

  • <scatter-gather doc:name="Scatter-Gather: Aggregate Services" timeout="10000">
  • <!-- Route 0: Flights API -->
  • <route>
  • <http:request config-ref="Flights_HTTP_Config" path="/flights" method="GET" doc:name="Get Flights">
  • <http:query-params><![CDATA[#[{'bookingId': vars.bookingId}]]]></http:query-params>
  • </http:request>
  • <set-variable variableName="flightsStatus" value="SUCCESS" doc:name="Set Flights Status"/>
  • </route>
  • <!-- Route 1: Hotels API -->
  • <route>
  • <http:request config-ref="Hotels_HTTP_Config" path="/hotels" method="GET" doc:name="Get Hotels">
  • <http:query-params><![CDATA[#[{'bookingId': vars.bookingId}]]]></http:query-params>
  • </http:request>
  • <set-variable variableName="hotelsStatus" value="SUCCESS" doc:name="Set Hotels Status"/>
  • </route>
  • <!-- Route 2: Rental Cars API -->
  • <route>
  • <http:request config-ref="Cars_HTTP_Config" path="/cars" method="GET" doc:name="Get Cars">
  • <http:query-params><![CDATA[#[{'bookingId': vars.bookingId}]]]></http:query-params>
  • </http:request>
  • <set-variable variableName="carsStatus" value="SUCCESS" doc:name="Set Cars Status"/>
  • </route>
  • </scatter-gather>
  • <!-- Transform the aggregated composite payload into a unified response -->
  • <ee:transform doc:name="Aggregate Response">
  • <ee:message>
  • <ee:set-payload><![CDATA[%dw 2.0
  • output application/json
  • --
  • {
  • bookingId: vars.bookingId,
  • flights: payload["0"].payload,
  • hotels: payload["1"].payload,
  • cars: payload["2"].payload,
  • flightResponseCode: payload["0"].attributes.statusCode
  • }]]></ee:set-payload>
  • </ee:message>
  • </ee:transform>
  • </flow>
  • 2. Structure of the Aggregated Composite Message

When all routes finish successfully, the resulting payload is an Object / Map containing zero-based string indices ( "0" , "1" , "2" , ...) corresponding to the declaration order of the <route> elements.

  • Detailed Structure of payload After Scatter-Gather: {
  • "0": {
  • "attributes": {
  • "statusCode": 200,
  • "headers": { "content-type": "application/json" }
  • },
  • "payload": {
  • "airline": "United",
  • "flightNumber": "UA-442",
  • "price": 350.00
  • }
  • },
  • "1": {
  • "attributes": {
  • "statusCode": 200,
  • "headers": { "content-type": "application/json" }
  • },
  • "payload": {
  • "hotelName": "Grand Hyatt",
  • "nights": 3,
  • "totalRate": 620.00
  • }
  • }
  • }

DataWeave Access Patterns:

Direct Indexed Navigation: payload["0"].payload accesses Route 0's payload body; payload["0"].attributes.statusCode accesses Route 0's attributes.

Dynamic Pluck Extraction: payload pluck ((routeMessage) -> routeMessage.payload) converts all route payloads into a flat JSON array [ { flight... }, { hotel... } ] .

Descendant Extraction ( .. ): payload..price extracts all fields named price across all child route payloads.

Important

payload["0"].payload vs payload[0] In Mule 4, the output of a successful Scatter-Gather is a Map of MuleMessage objects , NOT a simple JSON Array. Accessing payload[0] treats the payload as an indexed array and will fail or return null in DataWeave. You must access the route key as a map index: payload["0"].payload or payload."0".payload .

3. Variable Merging Rules & Collisions

How variables behave across parallel Scatter-Gather routes is a major certification focus: +-----------------------------------------------------------------------------------------+

  • | VARIABLE MERGING IN SCATTER-GATHER |
  • | |
  • | BEFORE SCATTER-GATHER: |
  • | vars.sharedVar = "ORIGINAL" |
  • | |
  • | ROUTE 0 MODIFICATIONS: ROUTE 1 MODIFICATIONS: |
  • | vars.sharedVar = "FROM_ROUTE_0" vars.sharedVar = "FROM_ROUTE_1" |
  • | vars.varRoute0 = "DATA_0" vars.varRoute1 = "DATA_1" |
  • | |
  • | AFTER SCATTER-GATHER (MERGED): |
  • | vars.varRoute0 = "DATA_0" (Cleanly merged) |
  • | vars.varRoute1 = "DATA_1" (Cleanly merged) |
  • | vars.sharedVar = NON-DETERMINISTIC! (Either "FROM_ROUTE_0" or "FROM_ROUTE_1") |
  • +-----------------------------------------------------------------------------------------+

Variable Rules Summary:

New Unique Variables: Any variable created in an individual route (e.g., vars.flightId in Route 0, vars.hotelId in Route 1) is cleanly merged into the parent flow's variable context and is available downstream.

Variable Collisions: If multiple parallel routes modify the same variable name (or modify an existing variable initialized before the router), the final value is non-deterministic (last thread to complete overwrites the value).

Best Practice: Always use route-prefixed or uniquely named variables (e.g., vars.route0_result , vars.route1_result ) inside parallel routes to eliminate collision risks.

4. Error Handling: MULE:COMPOSITE_ROUTING & Route Isolation

If ANY single route throws an unhandled error during execution:

Scatter-Gather immediately cancels normal aggregation.

Scatter-Gather raises a MULE:COMPOSITE_ROUTING error.

Execution jumps immediately to the enclosing flow's error handler. +-----------------------------------------------------------------------------------------+

  • | SCATTER-GATHER COMPOSITE ERROR SCENARIO |
  • | |
  • | Route 0: <http:request> ---> SUCCESS (HTTP 200 Flight Data) |
  • | Route 1: <http:request> ---> ERROR: HTTP:CONNECTIVITY (Hotel Service Unreachable!) |
  • | Route 2: <http:request> ---> SUCCESS (HTTP 200 Car Data) |
  • | |
  • | RESULT: Entire Scatter-Gather throws MULE:COMPOSITE_ROUTING |
  • | |
  • | IN ERROR HANDLER: |
  • | - error.description: Summary of composite failure |
  • | - error.childErrors: Map containing error objects from failed routes |
  • | error.childErrors["1"].errorType ===> HTTP:CONNECTIVITY |
  • | error.childErrors["1"].description ===> "HTTP GET failed: Connection refused" |
  • | - error.errorMessage.payload: Map containing both successes and errors |
  • +-----------------------------------------------------------------------------------------+
  • Route-Level Error Isolation Pattern (Using <try> )

In many business scenarios, a failure in one non-critical route (such as rental cars) should not abort the entire aggregation. To achieve fault tolerance, wrap the route's processors inside a <try> scope with an <on-error-continue> error handler: <scatter-gather doc:name="Fault-Tolerant Scatter-Gather">

  • <!-- Route 0: Flight Service -->
  • <route>
  • <http:request config-ref="Flights_HTTP_Config" path="/flights" method="GET" doc:name="Get Flights"/>
  • </route>
  • <!-- Route 1: Hotel Service with Try-Catch Isolation -->
  • <route>
  • <try doc:name="Try Hotel Lookup">
  • <http:request config-ref="Hotels_HTTP_Config" path="/hotels" method="GET" doc:name="Get Hotels"/>
  • <error-handler>
  • <on-error-continue type="ANY" doc:name="Catch Hotel Failure">
  • <logger level="WARN" message="#['Hotel lookup failed: ' ++ error.description]" doc:name="Log Warn"/>
  • <!-- Set a fallback empty payload so Route 1 succeeds -->
  • <set-payload value="#[{ 'hotels': [], 'status': 'UNAVAILABLE' }]" doc:name="Fallback Payload"/>
  • </on-error-continue>
  • </error-handler>
  • </try>
  • </route>
  • </scatter-gather>

Tip

How <on-error-continue> Protects Scatter-Gather Because <on-error-continue> catches the error inside Route 1 and returns a fallback payload, Route 1 completes successfully from the perspective of the Scatter-Gather router. Scatter-Gather aggregates the fallback payload into payload["1"].payload without throwing a MULE:COMPOSITE_ROUTING exception.

5. Exam Watch: Core Scatter-Gather Scenarios

Important

Composite Error Structure When a route fails, the overall error type is always MULE:COMPOSITE_ROUTING . Individual route failures are inspected using error.childErrors["0"] , error.childErrors["1"] , etc.

Warning

Concurrency & Thread Safety Parallel routes execute concurrently on separate threads. Never perform non-thread-safe modifications to external shared resources (like writing to the same local file or updating a shared static cache without locks) from inside parallel routes.

Tip

Timeout Attribute The timeout attribute on <scatter-gather timeout="5000"> is defined in milliseconds . If any route takes longer than the timeout to complete, Scatter-Gather aborts and raises a MULE:COMPOSITE_ROUTING containing a MULE:TIMEOUT child error.