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.

View Complete Node Conditions Schema

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.

Example: Order Processing Workflow ๐ŸŒŸ

Consider a typical e-commerce order process where you need conditional logic:

flowchart LR A([Check Stock]):::primary --> B{Stock > 0?}:::decision B -->|Yes| C([Process Payment]):::primary B -->|No| D([Check Backorder]):::primary D --> E{Available?}:::decision E -->|Yes| F([Create Backorder]):::secondary E -->|No| G([Notify Customer]):::secondary %% Add padding and width to nodes classDef primary fill:#4F46E5,stroke:#4338CA,color:#fff,rx:10,padding:10px classDef secondary fill:#6B7280,stroke:#4B5563,color:#fff,rx:10,padding:10px classDef decision fill:#8B5CF6,stroke:#7C3AED,color:#fff,rx:12,padding:10px

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 or G).

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:

  1. 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.
  2. continueTo (Choose Next Steps):

    • Provide an array of objects, each with a to (node ID) and a when (JSONata expression).
    • Expressions are evaluated in the order they appear.
    • If an expression is true, the specified to 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 in continueTo will be skipped.
  3. 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 matching continueTo condition.
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();

Structuring Your Conditions (Evaluation Order) ๐Ÿ”„

Graph Compose evaluates conditions in a specific order. Understanding this helps you structure your logic correctly:

  1. terminateWhen Check: All expressions in the terminateWhen array are checked first. If any are true, the workflow stops here.
  2. continueTo Check: If the workflow didn't terminate, the conditions in the continueTo array are checked in order.
    • The first condition that evaluates to true determines which node(s) listed in its to field will run.
    • If multiple conditions could be true, only the first one encountered matters for continueTo.
  3. 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 leave continueTo 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.