Skip to content

Sagas and Fan-out

The graph engine used loop nodes and gateway loops. The durable runtime uses Dart loops over recorded collections, forEach for durable fan-out, and saga for compensation.

forEach

dart
final results = await flow.forEach(
  id: 'lines',
  items: order.lines,
  key: (line) => line.id,
  body: (branch, line) => branch.serviceTask(reserveLine, line, id: 'reserve'),
);

Item keys must be stable. JSON forEach evaluates itemsBinding and exposes $.item inside the body.

Saga

dart
final booked = await flow.saga(
  id: 'booking',
  steps: [
    WorkflowSaga.step(
      id: 'reserve',
      execute: (ctx) => ctx.serviceTask(reserve, order, id: 'reserve'),
      compensate: (ctx, reservation) =>
          ctx.serviceTask(release, reservation, id: 'release'),
    ),
    WorkflowSaga.step(
      id: 'charge',
      execute: (ctx) => ctx.serviceTask(charge, order, id: 'charge'),
      compensate: (ctx, charge) =>
          ctx.serviceTask(refund, charge, id: 'refund'),
    ),
  ],
);

Compensation runs once, in reverse completion order. Each compensate is itself a durable service task with an idempotency key.

See Also