Skip to main content

ForEach

The ForEach Task enables parallel execution of a set of tasks for each item in an array. It works similar to the Parallel Task by treating each item as a new branch of execution. This enables faster processing than using a basic Procedural Loop pattern.

Using the ForEach task
Using the ForEach task

Consider a typical scenario where you would publish the entity updates to an external MDM. In the above example the ForEach task will iterate over the list of Entities retrieved from a Supergraph Task. For each entity it will check if an ExternalId field is defined before calling either the Create or Update APIs. Using an End task we can return the output for each iteration for evaluating later in the Flow.

Integration Flows can execute up to 5 parallel branches (array items) at once, allowing for the list to be processed up to 5x faster than using a procedural loop which processes one at a time.

Advanced Features

The ForEach Task supports Async Operations like HTTP Callback and EventIngress but does not allow for nesting Parallel Operations (e.g. running a ForEach or Parallel task within a ForEach task).

Configurable Options

The ForEach task requires the following configuration:

ForEach Task Options

ConfigurationDescription
Items to IterateTemplated Input defines json array to iterate over. Array can contain up to 1000 items.
Process InputTemplated Input defines the input to each branch of Execution
warning

A ForEach task can process up to 1000 items in an array. If the array contains more the task will throw an error at startup.

In scenarios where more than 1000 items must be processed you will need to wrap your ForEach loop in a procedural loop and process the total collection in batches.

Runtime

Tasks executing within a ForEach branch have additional details available at runtime via the Execution variable.

Runtime VariablesDataTypeDescription
Execution.BranchRequestJsonCurrent item from the array defined in "Items to Iterate"
Execution.ForEachRequestJsonBranch input object contains the following...
    CurrentIndexNumberItem's Index within the Items to Iterate array.
Use this to drive conditional logic such as adding a periodic wait for every 10 items.
    TotalCountNumberTotal count of items in the Items to Iterate array
    ProcessInputJsonProcess Input as defined in Task Configuration
Execution State within a Branch

Each branch maintains it's own Execution.State. Any State data available before the ForEach task will not be available from within the branch. Any details required can be mapped into the branch using the Process Input configuration.

State data within each branch will not be available after the branch completes. Please use an End Task to return any output from the current branch at the end of processing.

ASync Operations within a Branch

If you use HTTP Callbacks within a ForEach or Parallel task then each branch will get it's own async Id (Execution.AsyncId).

The ForEach task will not complete until all branches/instances (and nested async tasks) have completed.

Task Output

The ForEach task returns the following output as the final result of the flow execution.

Output VariablesDataTypeDescription
ResponsesJson ArrayArray of output from each branch
    StatusStringSuccess or Failure
    OutputJsonBranch Output, populated by an End Task at the end of the sequence of tasks
    ErrorMessageStringThis will only be populated if there is an exception (see Errors below).

Error Handling

The ForEach task will execute all instances in your array - even if a failure is encountered on one of the branches. If an exception occurs and you haven't configured Continue on Error in the Advanced tab of your ForEach task the execution will halt. Alternatively you can design your Flow to evaluate the branches and recover, or fail gracefully.

The ForEach task can throw the following exceptions:

  • ForEachInvalidRequest thrown when Items to Iterate is not a valid JSON Array or exceeds the maximum number of items.
  • ForEachTaskError denotes an exception during runtime while processing the branch (e.g. sub task throws an exception)

When there is an exception the task error output will include the following:

Error PropertiesDataTypeDescription
FailedIterationsJson ArrayArray of integers representing the failed iterations / branches.
e.g. FailedIterations [3, 8, 29] means responses[3], responses[8] and responses[29] will have status = failure.
ResponsesJson ArrayArray of output from each branch
    StatusStringSuccess or Failure
    OutputJsonBranch Output, populated by an End Task at the end of the sequence of tasks
    ErrorMessageStringIf there is an error, the error message will be included.

In the below design we've configured an error path to extract the Failed and Success responses using an Inline Transformer to store the results in Execution State. Similarly the successful path also extracts the responses to State. This allows us to handle the successful iterations in the event of a failure using logic as the normal path. Later in the Flow we can process the errors as needed.

Designing for errors
Designing for errors

Each task in the screenshot above uses the following JSONPath to extract the responses...

Store In State: ExecutionState ($.Results) = {{Task.forEachTask.Responses, $.Output}}
Extract Failed Instances: ExecutionState ($.Failures) = {{Task.forEachTask.Responses, $[?(@.Status == 'Success')].Output}}
Extract Success Instances: ExecutionState ($.Results) = {{Task.forEachTask.Error, $.Properties.Responses[?(@.Status == 'Success')]}}

Execution Details

The Execution Details page has been updated to show ForEach Iterations (branches) nested in the Execution Step Logs.

Parallel Operations in StepLogs
Parallel Operations in StepLogs
Description
1StepLog for ForEach task can be expanded to review each iteration/branch Flows
2List of Iterations
3List of tasks within the iteration/branch
4Input to iteration/branch. You'll see Execution BranchRequest and ForEach Request defined here.
5ForEach task output (Responses) from all iterations.