Skip to main content

For Each Step

The For Each Step is a container Step that executes exactly one child Step multiple times—once for each item in a provided array. This is particularly handy when you want to apply the same operation (e.g., fetching data, transforming inputs, sending requests) for multiple items.

Unlike a traditional loop, the For Each Step has a concurrency parameter that controls how many iterations can run in parallel. By default, it runs one iteration at a time (i.e., concurrency = 1). Increasing this value can speed up the overall process if parallelism is acceptable for your use case.

Key Points

  1. Single Child Step
    The For Each Step must have exactly one child Step defined in its children.

  2. Index-Based Invocations
    Each iteration of the child Step is given a unique reference:

    • childStepRef[0] for the first item,
    • childStepRef[1] for the second,
    • and so on.
  3. Template Variables
    Within the child Step definition, you can access:

    • {{ foreach.index }} for the current loop index,
    • {{ foreach.value }} for the current item in the array.
  4. Concurrency
    You can specify how many iterations to run in parallel by setting concurrency. For example, if you have 100 items and set concurrency = 10, then 10 items will be processed simultaneously until all 100 are complete.

  5. Failure Handling
    If any single iteration fails, the For Each Step does not immediately stop other iterations. It processes all items and then marks the Step as failed. This ensures more deterministic behavior, preventing partial completions and leaving tasks “stuck.”

Validations

  • Only One Child: If more than one child Step is defined, the For Each Step fails.
  • Allowed Child Types: If a forbidden Step type is used as the child, the For Each Step fails.

Typical Usage

  1. Add a For Each Step in your process definition.
  2. Provide an array via inputArray.
  3. Set concurrency to control parallel executions.
  4. Define a single child Step that references {{ foreach.value }} and optionally {{ foreach.index }} for dynamic inputs.
  5. Process subsequent Steps by referencing each iteration’s output using [index].

Example: Gathering Outputs

After the For Each Step finishes, you often want to collect outputs from each iteration. Suppose the For Each Step is called new_foreach_1, and its child Step is fetch_process_context. Here’s an example of a JavaScript Step that collects results from all iterations:

(steps, context) => {
const allResponses = [];
// Access the same array used in the For Each
for (let i = 0; i < steps.new_foreach_1.input.inputArray.length; i++) {
console.log('Reading', `fetch_process_context[${i}]`);
// Access each iteration's output
allResponses.push(
steps[`fetch_process_context[${i}]`].output.response
);
}

// Example transformation: gather just the 'error' and 'processId'
const filteredResponse = allResponses.map(item => {
return {
error: item.output?.error,
processId: item.processId
};
});

return filteredResponse; // or whatever structure you desire
}

Referencing Iteration Outputs

  • Within an iteration: Use {{ foreach.index }} and {{ foreach.value }}.
  • Outside an iteration: Use the child Step’s name plus [index] to retrieve the outcome of a specific iteration (e.g., fetch_process_context[2].output).

Sample Input

{
"inputArray": [
{
"id": 1,
"name": "Item A"
},
{
"id": 2,
"name": "Item B"
},
{
"id": 3,
"name": "Item C"
}
],
"concurrency": 2
}

The input array can also be scalar values

{
"inputArray": [
1,
2,
3
],
"concurrency": 2
}