Skip to content

Do While

"type" : "DO_WHILE"

The Do While task (DO_WHILE) sequentially executes a list of tasks as long as a given condition is true. The sequence of tasks gets executed before the condition is checked, even for the first iteration, just like a regular do.. while statement in programming.

Task parameters

Use these parameters in top level of the Do While task configuration.

Parameter Type Description Required / Optional
evaluatorType String The type of evaluator used. Supported types:
  • value-param: Evaluates a boolean input parameter in the Do While task.
  • graaljs: Evaluates JavaScript expressions and computes the value. Allows you to use ES6-compatible JavaScript.
If not specified, defaults to a built-in JavaScript evaluator.
Optional.
loopCondition String The condition that is evaluated after each iteration. The expression format depends on the evaluator type. For the value-param evaluator, the expression is the input parameter key. Otherwise, it is an ES6-compatible JavaScript expression. When using items for list iteration, the condition does not stop the loop, but this parameter must still be set. Required.
loopOver List[Task] The list of task configurations that will be executed as long as the condition is true. Required.

Input parameters

Use these parameters in the inputParameters section of the Do While task configuration.

Parameter Type Description Required / Optional
keepLastN Integer Number of most recent iterations to keep in the database and task output. Older iterations are automatically removed to prevent database bloat. When not specified, all iterations are retained (default behavior). This is useful for long-running loops with many iterations. Minimum value: 2. Lower values are treated as 2. Optional.
items List An array of items to iterate over in the loop. The number of iterations equals the list size, and no loop condition is needed to stop the loop. The current item is available in each iteration as ${do_while_ref.output.item}. If items is an empty list, the Do While task completes without executing the loop tasks. Optional.
captureOutput Available since: v5.3.0 and later Boolean Whether to capture and store per-iteration task outputs in the Do While task's output. Defaults to true. When set to false, iteration outputs are not aggregated and only iteration (and item, if applicable) is returned. Useful for large loops where storing every iteration's output would cause memory or performance issues. Optional.

Script expression

When using the graaljs evaluator, the loopCondition can be written as an ES6-compatible JavaScript function:

(function () {
  // statements
})();

Or:

(() => {
  // statements
})();

The expression must return a boolean value. If it returns any other type, such as a number or a string, the Do While task stays in progress and the workflow does not continue. To reference other input parameters or task outputs in the script, use the $ prefix, for example $.do_while_ref['iteration'].

Console logging

When using the graaljs evaluator, you can use console.log, console.info, and console.error inside the loopCondition script for debugging. The output appears in the Do While task's Logs tab. The console bridge accepts a single string argument. To include variable values, use string concatenation. For example:

{
  "name": "do_while",
  "taskReferenceName": "do_while_ref",
  "type": "DO_WHILE",
  "evaluatorType": "graaljs",
  "inputParameters": {
    "number": 3,
    "iteration": "${do_while_ref.output.iteration}"
  },
  "loopCondition": "(function () { console.log('Iteration: ' + $.iteration + ', limit: ' + $.number); return $.iteration < $.number; })();",
  "loopOver": [
    {
      "name": "http",
      "taskReferenceName": "http_ref",
      "type": "HTTP",
      "inputParameters": {
        "uri": "https://api.example.com/status",
        "method": "GET"
      }
    }
  ]
}

Console logging is available only when evaluatorType is set to graaljs. If evaluatorType is not set, console is not defined and the task fails.

JSON configuration

Here is the task configuration for a Do While task.

Counter-based iteration:

{
  "name": "do_while",
  "taskReferenceName": "do_while_ref",
  "inputParameters": {
    "keepLastN": 10
  },
  "type": "DO_WHILE",
  "loopCondition": "(function () {\n  if ($.do_while_ref['iteration'] < 5) {\n    return true;\n  }\n  return false;\n})();",
  "loopOver": [ // List of tasks to be executed in the loop
    {
        // task configuration
    },
    {
        // task configuration
    }
  ]
}

List iteration:

{
  "name": "do_while",
  "taskReferenceName": "do_while_ref",
  "type": "DO_WHILE",
  "loopCondition": "false",
  "inputParameters": {
    "items": "${workflow.input.myList}"
  },
  "loopOver": [
    {
      "name": "process_task",
      "taskReferenceName": "process_ref",
      "type": "SIMPLE",
      "inputParameters": {
        "item": "${do_while_ref.output.item}"
      }
    }
  ]
}

Output

The Do While task will return the following parameters.

Name Type Description
iteration Integer The number of iterations.

If the Do While task is in progress, iteration will show the current iteration number. When completed, iteration will show the final number of iterations.
item Any (If items is used as an input parameter) The value of the last item in the items array.

By default, a map is created for each iteration, keyed by its iteration number (e.g., 1, 2, 3), and contains the task outputs for all of the loopOver tasks.

Reading state in loopCondition

The loop condition receives the loop task's output under its taskReferenceName, and each task in the current loop iteration directly under that task's taskReferenceName. Loop-body task values are their output data maps; they are not wrapped in an additional output object.

// `loop` is the DO_WHILE reference; `check` is a loop-body task reference.
if ($.check['done'] == true || $.loop['iteration'] >= 10) { false; } else { true; }

In the completed task output, iteration data remains available under numeric keys such as loop.output.1.check. The direct bindings above apply only while evaluating loopCondition.

Using loop output in downstream tasks

After the Do While task completes, a downstream task can read the output of a loop task in two ways.

Last iteration: use the loop task's reference name without the iteration suffix. For example, ${task_ref.output.someField} returns the value from the last iteration.

Specific iteration: use the Do While task's output, keyed by iteration number. For example, ${do_while_ref.output['2'].task_ref.someField} returns the value from iteration 2. Replace do_while_ref with the Do While task's reference name, 2 with the iteration number, and task_ref with the loop task's reference name.

If keepLastN is set, only the last n iterations are available, and a reference to an earlier iteration returns null.

Execution

When a Do While loop is executed, each task in the loop will have its taskReferenceName concatenated with __i, with i as the iteration number starting at 1. If one of the loop tasks fails, the Do While task status will be set as FAILED, and upon retry, the iteration number will restart from 1. If an exception occurs while evaluating the loopCondition, the workflow fails and the reason for incompletion contains the script error.

Each loop task output is stored as part of the Do While task, indexed by the iteration value, allowing loopCondition to reference the output of a task for a specific iteration (e.g., $.LoopTask['iteration]['first_task']).

Iteration cleanup

For Do While loops with many iterations (e.g., 100+ iterations), storing all iteration data can lead to database bloat, memory exhaustion, and performance degradation. The keepLastN input parameter provides automatic cleanup of old iterations.

How it works:

When keepLastN is specified in inputParameters, Conductor automatically removes old iteration data from both the database and the task output once the number of iterations exceeds the keepLastN value. For example, with keepLastN: 5:

  • Iterations 1-5: All iterations kept
  • Iteration 6: Iteration 1 is removed, keeping iterations 2-6
  • Iteration 7: Iteration 2 is removed, keeping iterations 3-7
  • And so on...

Important considerations:

  • Opt-in behavior: Cleanup only occurs when keepLastN is explicitly set. Without this parameter, all iterations are retained (default behavior).
  • Backward compatibility: Existing workflows without keepLastN continue to work unchanged.
  • Output data: Only the most recent N iterations will be available in the task output. Older iterations are permanently removed.
  • Loop condition: Ensure your loopCondition only references recent iterations if using keepLastN, as older iteration data will not be available.
  • Best practices:
  • For loops expected to run 100+ iterations, consider setting keepLastN to a reasonable value (e.g., 5-10).
  • Choose a keepLastN value that balances memory usage with your need to access historical iteration data.
  • If your loopCondition needs to reference older iterations, ensure keepLastN is set high enough to retain that data.

Example with cleanup:

{
  "name": "long_running_loop",
  "taskReferenceName": "long_running_loop_ref",
  "inputParameters": {
    "keepLastN": 5
  },
  "type": "DO_WHILE",
  "loopCondition": "if ($.long_running_loop_ref['iteration'] < 1000) { true; } else { false; }",
  "loopOver": [
    {
      "name": "process_item",
      "taskReferenceName": "process_item_ref",
      "type": "SIMPLE"
    }
  ]
}

In this example, even though the loop runs 1000 iterations, only the last 5 iterations are kept in the database and output at any given time, preventing database bloat.

Examples

Here are some examples for using the Do While task.

List iteration (simplified approach)

When you have a list of items to iterate over, use the items parameter for a simpler approach that doesn't require manual counter management.

{
  "name": "process_items",
  "taskReferenceName": "process_items_ref",
  "type": "DO_WHILE",
  "loopCondition": "false",
  "inputParameters": {
    "items": "${workflow.input.itemList}"
  },
  "loopOver": [
    {
      "name": "http",
      "taskReferenceName": "http_ref",
      "inputParameters": {
        "http_request": {
          "uri": "https://api.example.com/process",
          "method": "POST",
          "body": {
            "item": "${process_items_ref.output.item}"
          }
        }
      },
      "type": "HTTP"
    }
  ]
}

In this example: - The loop automatically iterates through each item in workflow.input.itemList - item contains the current item (for example, the first iteration gets itemList[0]) - If the input list is empty ([]), the Do While task completes immediately without executing loop tasks - The loop runs once for each item. A loopCondition cannot stop it early.

Using a basic script (counter-based iteration)

In this example task configuration, the Do While task evaluates two criteria:

{
    "name": "Loop",
    "taskReferenceName": "LoopTask",
    "type": "DO_WHILE",
    "inputParameters": {
      "value": "${workflow.input.value}"
    },
    "loopCondition": "if ( ($.LoopTask['iteration'] < $.value ) || ( $.first_task['response']['body'] > 10)) { false; } else { true; }",
    "loopOver": [
        {
            "name": "firstTask",
            "taskReferenceName": "first_task",
            "inputParameters": {
                "http_request": {
                    "uri": "http://localhost:8082",
                    "method": "POST"
                }
            },
            "type": "HTTP"
        },{
            "name": "secondTask",
            "taskReferenceName": "second_task",
            "inputParameters": {
                "http_request": {
                    "uri": "http://localhost:8082",
                    "method": "POST"
                }
            },
            "type": "HTTP"
        }
    ],
    "startDelay": 0,
    "optional": false
}

Assuming three executions occurred (first_task__1, first_task__2, first_task__3, second_task__1, second_task__2, and second_task__3), the Do While task will return the following will produce the following output:

{
    "iteration": 3,
    "1": {
        "first_task": {
            "response": {},
            "headers": {
                "Content-Type": "application/json"
            }
        },
        "second_task": {
            "response": {},
            "headers": {
                "Content-Type": "application/json"
            }
        }
    },
    "2": {
        "first_task": {
            "response": {},
            "headers": {
                "Content-Type": "application/json"
            }
        },
        "second_task": {
            "response": {},
            "headers": {
                "Content-Type": "application/json"
            }
        }
    },
    "3": {
        "first_task": {
            "response": {},
            "headers": {
                "Content-Type": "application/json"
            }
        },
        "second_task": {
            "response": {},
            "headers": {
                "Content-Type": "application/json"
            }
        }
    }
}

Using the iteration key in a loop task

Sometimes, you may want to use the Do While iteration value/counter inside your loop tasks. In this example, an API call is made to a GitHub repository to get all stargazers and each iteration increases the pagination.

To evaluate the current iteration, the parameter $.get_all_stars_loop_ref['iteration'] is used in loopCondition. In the HTTP task embedded in the loop, ${get_all_stars_loop_ref.output.iteration} is used to define which page the API should return.

{
    "name": "get_all_stars",
    "taskReferenceName": "get_all_stars_loop_ref",
    "inputParameters": {
        "stargazers": "4000"
    },
    "type": "DO_WHILE",
    "loopCondition": "if ($.get_all_stars_loop_ref['iteration'] < Math.ceil($.stargazers/100)) { true; } else { false; }",
    "loopOver": [
        {
            "name": "100_stargazers",
            "taskReferenceName": "hundred_stargazers_ref",
            "inputParameters": {
                "counter": "${get_all_stars_loop_ref.output.iteration}",
                "http_request": {
                    "uri": "https://api.github.com/repos/ntflix/conductor/stargazers?page=${get_all_stars_loop_ref.output.iteration}&per_page=100",
                    "method": "GET",
                    "headers": {
                        "Authorization": "token ${workflow.input.gh_token}",
                        "Accept": "application/vnd.github.v3.star+json"
                    }
                }
            },
            "type": "HTTP"
        }
    ]
}

Limitations

There are several limitations for the Do While task:

  • Branching—Within a Do While task, branching using Switch, Fork/Join, Dynamic Fork tasks are supported. However, since the loop tasks will be executed within the scope of the Do While task, any branching that crosses outside its scope will not be respected.
  • Nested loops—Nested Do While tasks are not supported. To achieve a similar functionality as a nested loop, you can use a Sub Workflow task inside the Do While task.
  • Isolation group execution—Isolation group execution is not supported. However, domain is supported for loop tasks inside the Do While task.