Skip to content

Control Flow Patterns

Standard patterns for controlling workflow execution.

Basic Patterns

Sequence

Tasks execute one after another:

dart
builder
    .start('begin')
    .task('step1', ...)
    .task('step2', ...)
    .task('step3', ...)
    .end('done')
    .connect('begin', 'step1')
    .connect('step1', 'step2')
    .connect('step2', 'step3')
    .connect('step3', 'done');

Conditional Branching (Exclusive)

Route to exactly ONE path:

dart
builder
    .start('begin')
    .task('evaluate', ...)
    .oneOf('decide', [
      Branch.whenFn((o) => o['score'] >= 80, then: 'excellent'),
      Branch.whenFn((o) => o['score'] >= 60, then: 'good'),
      Branch.otherwise(then: 'needsWork'),
    ])
    .task('excellent', ...)
    .task('good', ...)
    .task('needsWork', ...)
    .end('done');

Multi-Choice (Inclusive)

Route to ONE OR MORE paths:

dart
builder
    .anyOf('notify', ['sendEmail', 'sendSms', 'sendPush']);

Parallel Execution

Execute ALL paths concurrently:

dart
builder
    .allOf('fork', ['taskA', 'taskB', 'taskC'])
    .task('taskA', ...)
    .task('taskB', ...)
    .task('taskC', ...)
    .allOf('join', ['afterJoin'])
    .connect('taskA', 'join')
    .connect('taskB', 'join')
    .connect('taskC', 'join');

Synchronization Patterns

Parallel Split + Synchronizing Merge

dart
// Fork to 3 parallel branches
builder.allOf('split', ['validateData', 'checkInventory', 'verifyPayment']);

// Each branch does its work
builder.task('validateData', ...);
builder.task('checkInventory', ...);
builder.task('verifyPayment', ...);

// Join waits for ALL branches
builder.allOf('synchronize', ['processOrder']);

// Edges from branches to join
builder.connect('validateData', 'synchronize');
builder.connect('checkInventory', 'synchronize');
builder.connect('verifyPayment', 'synchronize');

Discriminator (First Wins)

Take the first branch to complete:

dart
// Simulate with inclusive gateway
builder.anyOf('race', ['useFast', 'useSlow']);

Deferred Choice

Wait for one of multiple events:

dart
builder
    .signalWait('waitForAction', signal: 'user_action', storeAs: 'action')
    .oneOf('routeAction', [
      Branch.whenFn((o) => o['action']?['type'] == 'approve', then: 'handleApprove'),
      Branch.whenFn((o) => o['action']?['type'] == 'reject', then: 'handleReject'),
      Branch.whenFn((o) => o['action']?['type'] == 'timeout', then: 'handleTimeout'),
    ]);

Error Handling Patterns

Try-Catch

dart
builder
    .task('riskyOperation', ...)
    .oneOf('checkResult', [
      Branch.whenFn((o) => o['success'] == true, then: 'continueNormal'),
      Branch.whenFn((o) => o['error']?['retryable'] == true, then: 'retry'),
      Branch.otherwise(then: 'handleError'),
    ]);

Compensation

dart
// If step fails, run compensation
builder
    .task('chargePayment', ...)
    .task('fulfillOrder', ...)
    .oneOf('checkFulfillment', [
      Branch.whenFn((o) => o['fulfilled'] == true, then: 'complete'),
      Branch.otherwise(then: 'compensate'),
    ])
    .task('compensate', name: 'Refund Payment', ...)
    .end('complete')
    .end('compensated');

Gateway Summary

PatternGatewayBehavior
Exclusive ChoiceoneOf (XOR)ONE path based on condition
Simple MergeoneOf (XOR)Merge exclusive paths
Multi-ChoiceanyOf (OR)ONE+ paths based on conditions
Parallel SplitallOf (AND)ALL paths concurrently
SynchronizationallOf (AND)Wait for ALL branches

Next Steps