Skip to content

Vyuh Workflows ​

Durable Process Orchestration

Write long-running processes as typed Dart. Operations, requested work, events, timers, and child flows are durable boundaries that resume after crashes, restarts, or worker changes.

Why Durable Workflows?

Deterministic Replay

Workflows are Dart functions. After a restart, the runtime replays recorded history and stops at the next unresolved durable await.

Assigned Work

Work items wait in storage, not in a process. Any eligible actor can claim and respond to requested work.

Transactional History

Runs, events, and commands commit together. PostgreSQL leases, fencing, and SKIP LOCKED keep competing workers honest.

One Vocabulary, Two Surfaces

Author in typed Dart or constrained JSON. Both produce a WorkflowHandler that executes in WorkflowRuntime.

Getting Started

Core Concepts

Durable Vocabulary

AwaitPurpose
OperationIdempotent automated work
WorkAssigned work for any actor
EventTyped communication between execution paths
TimerDurable sleep
Child workflowCall, spawn, and join

Patterns & Examples

Quick Example ​

dart
import 'package:vyuh_workflow_engine/vyuh_workflow_runtime.dart';

final reserve = Operation<Order, Reservation, OrderFailure>(
  name: 'orders.reserve',
  version: 1,
  input: orderSchema,
  output: reservationSchema,
  failure: orderFailureSchema,
);

final approve = Work<Reservation, Approval>(
  name: 'orders.approve',
  input: reservationCodec,
  response: approvalCodec,
);

final orderApprovalDefinition = Workflow<
  Order,
  Result,
  OrderFailure
>(
  code: 'orders.approval',
  version: 1,
  input: orderSchema,
  output: resultSchema,
  failure: orderFailureSchema,
);

final orderApprovalHandler = orderApprovalDefinition.implement(
  fingerprint: buildFingerprint,
  execute: (workflow, order) async {
    final reservation = await workflow.perform(
      reserve,
      order,
      id: 'reserve',
      schedule: WorkflowSchedule.exponential(
        const Duration(seconds: 1),
        attempts: 3,
      ),
    );
    final decision = await workflow.request(
      approve,
      reservation,
      id: 'approve',
      title: 'Approve order',
      audience: const Audience(
        roleIds: ['order-approver'],
      ),
    );
    return decision.approved ? Result.approved() : Result.rejected();
  },
);

final runtime = WorkflowRuntime(
  storage: InMemoryWorkflowStorage(),
  modules: [
    WorkflowModule(
      name: 'orders',
      workflows: [orderApprovalHandler],
      operations: [
        reserve.implement(
          (operation, order) => reservationService.reserve(
            order,
            idempotencyKey: operation.context.idempotencyKey,
          ),
        ),
      ],
      work: [approve],
    ),
  ],
);

final run = await runtime.start(orderApprovalHandler, order);

New application code imports vyuh_workflow_runtime.dart. The graph subsystem is explicit through Legacy* names and is separate from durable authoring.

For CDX approvals, use ApprovalWorkflowHandlerFactory from cdx_workflow_templates and respond to work through the workflow service. See Approval Workflows and CDX Integration.