7. Interpreter
Orchestration
The engine has one piece of run logic, the interpreter. It is a Durable Task Scheduler orchestration named WorkflowInterpreter. Every run, of every definition, is one instance of it. There is no code per workflow.
Durable Task Scheduler
Durable Task Scheduler (DTS) is an Azure service. It stores the history of each orchestration: which steps have run and what they returned. When the engine process restarts, DTS replays that history so the orchestration resumes exactly where it stopped. DTS also provides:
- Timers: a run can wait for a duration without holding a process.
- External events: a run can wait for a named signal, such as a human decision or a worker result.
- Sub-orchestrations: a run can start another run and wait for it.
- One-at-a-time processing per run: two signals for the same run never interleave.
Because DTS provides these, the engine has no lock service, no background sweeper, and no reconciliation job.
Execution loop
load the definition and instruction texts (cached)
record the run as RUNNING
for each task the Decider returns:
resolve the task's input references
switch on the task type:
activity types -> call the activity, with retry settings from the task definition
SWITCH -> pick a branch, continue inside it
FORK_JOIN -> run branches in parallel, wait for all
DO_WHILE -> repeat with a bound and a condition
WAIT -> create a timer
HUMAN -> wait for the external event named after the task, with timeout
SUB_WORKFLOW -> start a child WorkflowInterpreter and wait
WORKER -> enqueue the task, then wait for the external event named by task id
SET_VARIABLE -> update variables
TERMINATE -> finish with the given status
record the task's row
record the run as COMPLETED or FAILED with its outputs
The Decider is a class with no I/O: definition and completed tasks in, next task out. It is unit tested on its own.
Timeouts and retries
Task-level settings live in the task definition (page 9). Run-level settings live in the workflow definition:
| Setting | Effect |
|---|---|
timeoutSeconds on the workflow | A DTS timer at start. On expiry, TIME_OUT_WF fails the run; ALERT_ONLY records a metric and continues. |
retryCount, retryLogic, retryDelaySeconds on a task definition | Activity tasks: DTS retry options. Worker tasks: re-queued with a scheduled delay. |
optional: true on a task | The task's failure is recorded but the run continues. |
Failure workflow
When a run ends FAILED, TIMED_OUT, or TERMINATED and its definition names a failureWorkflow, the engine starts it with input:
{ "workflowId": "...", "reason": "...", "failedTaskId": "...",
"failureStatus": "FAILED", "workflowInput": { } }
Statuses
Run: RUNNING, PAUSED, COMPLETED, FAILED, TIMED_OUT, TERMINATED.
Task: SCHEDULED, IN_PROGRESS, COMPLETED, COMPLETED_WITH_ERRORS, FAILED, FAILED_WITH_TERMINAL_ERROR (no retry), TIMED_OUT, CANCELED, SKIPPED.
Payload offload
When an input or output exceeds a size threshold (default 10 KB), the engine stores it in Blob and keeps the URL in the record. Above a hard maximum (default 10 MB) the step fails with a clear reason. Thresholds exist for workflow input, workflow output, task input, and task output. Workers can upload large outputs directly using the URL from GET /api/tasks/external-storage-location and post only the URL.