Flow Control: Directing Your Workflow ๐ฎ
Learn how to guide your workflow's execution path using conditional logic. Make your workflows smarter and more efficient by deciding which nodes run based on the results of previous steps.
๐ Key Concepts:
- Use
conditions.terminateWhento stop the workflow at a node based on specific criteria. - Use
conditions.continueToto explicitly choose which downstream nodes should run next. - Nodes depending on the current one will run automatically unless skipped by
continueToor if the workflow terminates. - Conditions use JSONata expressions within
{{ }}syntax. terminateWhenconditions are always checked first.
Why Use Flow Control? ๐ค
Conditional flow control gives you the power to:
- Make Decisions: Branch your workflow based on data (e.g., process payment only if stock is available).
- Increase Efficiency: Skip nodes that aren't needed in certain scenarios.
- Handle Complexity: Implement sophisticated business logic with clear pathways.
- Build Resilience: Create workflows that adapt to different situations or errors.
๐ก Think of flow control as adding decision points to your workflow map, guiding the execution like a traffic controller.
Example: Order Processing Workflow ๐
Consider a typical e-commerce order process where you need conditional logic:
In this scenario:
- The workflow first checks stock (
A). - Decision Point (
B): If stock is zero, it skips payment (C) and proceeds to check backorders (D). This requires conditional logic. - Decision Point (
E): Based on backorder availability, it takes different actions (ForG).
How to Implement Conditional Branching โจ
You define conditions within a node's configuration using the conditions object. There are two main ways to control the flow:
-
terminateWhen(Stop Execution):- Provide an array of JSONata expressions.
- If any expression evaluates to
true, the workflow stops execution after this node completes. - No further downstream nodes will run.
- This is checked before
continueTo. Ideal for handling critical errors or final states.
-
continueTo(Choose Next Steps):- Provide an array of objects, each with a
to(node ID) and awhen(JSONata expression). - Expressions are evaluated in the order they appear.
- If an expression is
true, the specifiedtonode is scheduled to run. - Crucially: If
continueTois defined, only the nodes specified in matching conditions and nodes that automatically run (see below) will execute next. Any dependent nodes not matched incontinueTowill be skipped.
- Provide an array of objects, each with a
-
Automatic Execution (Default Behavior):
- If a node B depends on node A (e.g.,
dependencies: ["A"]), B will automatically run after A completes unless:- Node A terminates the workflow via
terminateWhen. - Node A uses
continueTo, and node B is not listed in any matchingcontinueTocondition.
- Node A terminates the workflow via
- If a node B depends on node A (e.g.,
import { GraphCompose } from '@graph-compose/client';
const workflow = new GraphCompose()
.node('check_status')
// Assume 'process_data' and 'log_metrics' depend on 'check_status'
.get('/status') // Example HTTP call
.withConditions({
// 1. Termination check (runs first)
terminateWhen: [
'{{ status = "maintenance" }}' // Stop if in maintenance
],
// 2. Explicit continuation (if not terminated)
continueTo: [
{
// Only run 'process_data' if status is 'ready'
to: 'process_data',
when: '{{ status = "ready" }}'
}
// Note: 'log_metrics' will NOT run if status is 'ready',
// because 'continueTo' is defined but doesn't include it.
]
})
.end()
.node('process_data')
.dependencies(['check_status'])
// ... config ...
.end()
.node('log_metrics')
.dependencies(['check_status'])
// This node only runs if status is NOT 'maintenance' (not terminated)
// AND status is NOT 'ready' (because 'continueTo' skips it then).
// It runs automatically in other cases (e.g., status='pending').
.end();
โ ๏ธ Important Reminders:
terminateWhentakes priority. If it matches,continueTois ignored.- If you use
continueTo, you must explicitly list all desired downstream paths for the matching conditions. Dependent nodes not listed will be skipped. - If
conditionsis omitted entirely, all dependent nodes run automatically. - All condition expressions (
when,terminateWhen) must evaluate to a boolean (trueorfalse). - Use the JSONata Playground to test your expressions. Graph Compose also validates them.
Structuring Your Conditions (Evaluation Order) ๐
Graph Compose evaluates conditions in a specific order. Understanding this helps you structure your logic correctly:
terminateWhenCheck: All expressions in theterminateWhenarray are checked first. If any aretrue, the workflow stops here.continueToCheck: If the workflow didn't terminate, the conditions in thecontinueToarray are checked in order.- The first condition that evaluates to
truedetermines which node(s) listed in itstofield will run. - If multiple conditions could be true, only the first one encountered matters for
continueTo.
- The first condition that evaluates to
- Automatic Execution: Any nodes that depend on the current node and were not explicitly skipped by a matching
continueTocondition will run automatically.
import { GraphCompose } from '@graph-compose/client';
const workflow = new GraphCompose()
.node('check_order')
.withConditions({
terminateWhen: [
'{{ order.status = "cancelled" }}' // Check first
],
continueTo: [
{
// More specific case first
to: 'handle_flagged_order',
when: '{{ order.isFlagged = true }}'
},
{
// General case if not flagged
to: 'process_standard_order',
when: '{{ order.status = "pending" }}'
}
// If status is 'pending' but isFlagged is true,
// only 'handle_flagged_order' runs due to order.
]
})
.end();
// ... dependent nodes 'handle_flagged_order', 'process_standard_order'
Best Practices ๐ก
Follow these tips for clear and effective flow control:
- โ
Use
terminateWhenfor clear stopping points (errors, final states). - ๐ฏ Use
continueTowhen you need explicit control over which specific path(s) to take next, potentially skipping other dependents. - ๐ค Omit
conditionsor leavecontinueToempty if all direct dependents should run by default. - ๐ Order
continueToconditions from most specific to most general if they might overlap. - ๐ฏ Ensure all conditions evaluate to boolean (
true/false). Use the JSONata playground!
Need to Wait? Polling Conditions โณ
If your workflow needs to pause and wait for an external process (like a long-running job), simple branching isn't enough. Check out our Polling Conditions guide for handling asynchronous waits, status checks, and resource availability.