Skip to content

Orchestrator Flow

How the orchestrator manages the full lifecycle of a workflow instance — from case.created through to case.workflow.completed.

Concepts

  • WorkflowDefinition — a versioned, org- and product-scoped graph of steps. Steps reference a kind (e.g. gate_on_consent, run_ai_review, request_human_review, emit_final). Definitions are authored as drafts, validated, then published. Only one definition per org+product can be active at a time.
  • WorkflowInstance — a running snapshot of a definition for a specific case. The definition is snapshotted at creation so in-flight instances are not affected by definition changes.
  • WorkflowStep — one executed step within an instance. Records the step's kind, dispatched correlationId, status, and context snapshot.
  • WorkflowEvent — an idempotency inbox. Every consumed completion event is written here before processing; duplicate events are silently dropped.

Lifecycle steps

  1. Triggercase.created arrives on the Redis Stream. The CaseCreatedConsumer writes a WorkflowEvent row (idempotency), then calls DefinitionsService.findActiveFor(orgId, productId).

  2. InstantiationInstancesService.create creates a WorkflowInstance with a snapshot of the definition. TimeoutSchedulerService schedules a BullMQ deadline job using the definition's workflowTimeoutSeconds. If the instance mode is active, InstancesService.start immediately dispatches the first step.

  3. DispatchDispatcherService.dispatch maps a step's kind to an event type (e.g. gate_on_consentconsent.check.requested) and calls publishEvent from @sa-platform/events. A correlationId (UUID) is generated and stored with the WorkflowStep row so the completion event can be matched back.

  4. CompletionCompletionEventsConsumer reads from all completion streams (consent.check.completed, ai_review.completed, ai_review.failed, human_review.completed, human_review.failed, etc.) in a single loop. It resolves the correlationId to a WorkflowInstance + WorkflowStep, determines the outcome (on_pass, on_fail, on_complete, on_failure), and calls InstancesService.handleCompletion.

  5. TransitionhandleCompletion evaluates the definition's transition expression for the current step and outcome. If more steps remain, it dispatches the next. If the resolved step kind is emit_final, the dispatcher publishes case.workflow.completed and the instance is marked completed.

  6. Manual interventions — Operators can halt, resume, cancel, supersede, or retry-step an instance via the workflow-instances REST endpoints. Halt and resume transitions are recorded in WorkflowIntervention with an optional ReasonCode.

Step kinds and dispatched events

Step kind Dispatched event Completion event(s)
gate_on_consent consent.check.requested consent.check.completed
require_images case.images_check.requested case.images_check.completed
run_ai_review ai_review.requested ai_review.completed, ai_review.failed
request_human_review human_review.requested human_review.completed, human_review.failed
set_case_status case.set_status.requested case.set_status.completed
emit_webhook workflow.webhook_emit.requested workflow.webhook_emit.completed
emit_final case.workflow.completed (terminal)

Code paths

  • case.created consumer: services/orchestrator/src/consumers/case-created.consumer.ts
  • Completion events consumer: services/orchestrator/src/consumers/completion-events.consumer.ts
  • Dispatcher: services/orchestrator/src/dispatcher/dispatcher.service.ts
  • Instance lifecycle: services/orchestrator/src/instances/instances.service.ts
  • Manual interventions: services/orchestrator/src/instances/interventions.service.ts
  • Timeout scheduler: services/orchestrator/src/scheduler/timeout-scheduler.service.ts

The Mermaid sequence source is at docs/diagrams/orchestrator-sequence.mmd.