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.terminateWhen
to stop the workflow at a node based on specific criteria. - Use
conditions.continueTo
to explicitly choose which downstream nodes should run next. - Nodes depending on the current one will run automatically unless skipped by
continueTo
or if the workflow terminates. - Conditions use JSONata expressions within
{{ }}
syntax. terminateWhen
conditions 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 (F
orG
).
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 specifiedto
node is scheduled to run. - Crucially: If
continueTo
is defined, only the nodes specified in matching conditions and nodes that automatically run (see below) will execute next. Any dependent nodes not matched incontinueTo
will 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 matchingcontinueTo
condition.
- 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:
terminateWhen
takes priority. If it matches,continueTo
is 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
conditions
is omitted entirely, all dependent nodes run automatically. - All condition expressions (
when
,terminateWhen
) must evaluate to a boolean (true
orfalse
). - 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:
terminateWhen
Check: All expressions in theterminateWhen
array are checked first. If any aretrue
, the workflow stops here.continueTo
Check: If the workflow didn't terminate, the conditions in thecontinueTo
array are checked in order.- The first condition that evaluates to
true
determines which node(s) listed in itsto
field 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
continueTo
condition 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
terminateWhen
for clear stopping points (errors, final states). - ๐ฏ Use
continueTo
when you need explicit control over which specific path(s) to take next, potentially skipping other dependents. - ๐ค Omit
conditions
or leavecontinueTo
empty if all direct dependents should run by default. - ๐ Order
continueTo
conditions 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.