Skip to content

Workflow runtime API and C#

Use the application-automation services for authorized process operations. The Workflow SDK contract is 7.1.0 and Engine is 5.2.0; YAML remains version 2. Configure a Definition and publish a revision before starting it. For the WebApp, see Using Workflows.

All HTTP routes are relative to WORKSPACE_API_BASE_URL. The installed Runtime OpenAPI is authoritative; the generated reference contains complete request, response, enum and error schemas.

Inject IWorkflowInstanceAutomationCommandService and IWorkflowInstanceAutomationQueryService from Moltaro.Package.NET.Workflow.Automation. Generated projects register them automatically. Supported function contexts are Action, Command, HttpEndpoint, Job and TriggerHandler; Validation and BeforeSaveMutation are rejected. These services own a separate application transaction and do not join a transaction opened on your generated EF context.

using Moltaro.Package.NET.Workflow.Automation;
using Moltaro.Package.NET.Workflow.Instances;
public static async Task<string> StartReviewAsync(
IWorkflowInstanceAutomationCommandService commands,
string definitionId, string subjectId, string operationId,
CancellationToken cancellationToken)
{
var result = await commands.StartAsync(
new StartWorkflowInstanceRequest(definitionId, subjectId, operationId),
cancellationToken);
result.ThrowIfFailed();
return result.Data!.WorkflowInstanceId!;
}

The request waits for admission and its transaction to commit. Execution then continues in the Worker. A successful Start receipt does not mean the instance has completed. Keep the returned instance and command IDs. Use GetAsync(instanceId) to inspect the instance and its ActiveNodes; GetCommandAsync(commandId) reads the safe receipt state and error code. Command states are Ready, Processing, Completed, Faulted and Skipped, with the first two non-terminal. Instance Running includes waits; Faulted needs administrative recovery. Suspended retains a paused run. Completed and Canceled are terminal instance states. Use bounded polling with backoff when waiting for completion, and stop on a terminal state or your application’s timeout.

ListAsync(new WorkflowInstanceListRequest { ... }) returns one authorized page of processes: the caller sees a process when it may view the Subject or administers the Definition, and every filter (Definition, states, start range, waiting for input, number search, RequiresMyAction), the sort allowlist and the count are applied in the database before pagination (page size at most 100). Rows without Subject View are technical: no Subject, node titles or choices. ListDefinitionsAsync() lists Definitions usable as a list filter without configuration permissions. GetExecutionViewAsync(instanceId) returns the process’s pinned graph (nodes, outputs, authored positions and routes) together with aggregated execution facts: visit counts per node, the unfinished visits, and how often each exact output was traversed. It is authorized like GetAsync and uses the same technical projection without Subject View; it never exposes admission rules, messages or command payloads.

To answer User Input, take the exact waiting visit’s ID and RowVersion and pass new RespondWorkflowNodeRequest(choiceKey, visit.RowVersion, operationId) to RespondAsync(instanceId, visit.Id, request). A node can be visited again, so do not use NodeKey as the response identity. Available actions and choice keys come from the runtime query; the command rechecks current authority.

Explicit Start and User Input share the same Responsible, inherited-permission or Security DSL evaluator and require current Subject View. Ordinary calls use the invoking user. Trusted Jobs and TriggerHandlers use the platform’s system execution mode; personal admission may be bypassed, but activation mode, precondition, choices and unfinished-instance restrictions still apply. Client actor IDs or flags cannot request that mode.

Implicit activation is exercised by changing a Subject through its application commands. For example, creating an Entity through IEntityAutomationCommandService publishes the real resource event. Inserting a WorkflowInstance through EF is not activation. Delayed events use current record data and the Active revision at admission. Settings do not backfill old records, and replaying an event cannot restart a completed process.

Each due CRON occurrence enqueues a function job, which invokes the same runtime facade. Correlate that function’s jobs/runs by ScheduleId; track Workflow progress separately by its instance and command IDs. See asynchronous operations for the function job/run contract.

Keep OperationId and payload unchanged for an exact retry. Reusing an operation identity for changed data conflicts. New starts conflict while any instance of the same Definition/Subject is Running, Faulted or Suspended, across revisions. New Active revisions do not alter an existing instance. Worker restart preserves Delay, User Input and durable event observations; strict transactional DevLog records each completed log visit once.

The equivalent base route is /api/workspace/workflow/runtime on WORKSPACE_API_BASE_URL:

MethodRoutePurpose
GETsubjects/{definitionId}/{subjectObjectId}Discover processes and manual start eligibility
POSTinstancesStart with WorkflowDefinitionId, SubjectObjectId and OperationId
GETinstancesList authorized processes with filtering and pagination
GETdefinitionsList Definitions available as process-list filters
GETinstances/{id}Read instance and active visits
GETinstances/{id}/history?afterSequence=0&pageSize=50Read ordered history; pages are capped at 100
GETinstances/{id}/execution-viewRead the pinned graph with aggregated visit and transition facts
POSTinstances/{id}/node-instances/{visitId}/responseAnswer the exact User Input wait
POSTinstances/{id}/cancelAdministrative cancellation
POSTinstances/{id}/retryRecover a Faulted instance
POSTinstances/{id}/suspendPause a Running or Faulted instance
POSTinstances/{id}/resumeRestore the state remembered before suspension
GETcommands/{id}Read safe command state

The Definition Security tab assigns existing roles and groups as runtime administrators. Global administrators and Workflow Configuration Managers may edit these assignments. Only a global administrator or an administrator of this Definition may Cancel, Retry, Suspend or Resume. Runtime administration does not grant access to Subject fields or User Input. Administrators without Subject View receive a technical process projection without business data.

All four controls require Reason (trimmed, 1–2048 characters), ExpectedInstanceRowVersion and a string OperationId (trimmed, 1–128 characters). C# uses WorkflowInstanceAdministrationRequest; call SuspendAsync or ResumeAsync on the command service. Preserve the exact request when retrying after a lost response. A changed request needs a new OperationId and current version.

Suspend retains the same revision, visits, choices and timer deadlines. Time continues: after Resume, an overdue timer proceeds and an unexpired timer waits only its remaining time. PreSuspendStatus tells whether Resume will restore Running or Faulted. Faulted still needs a separate Retry. New User Input responses and Retry are unavailable while suspended; Cancel remains terminal.

Cancel and Suspend are available even while Workflow is disabled or the Subject is unavailable. Resume and Retry require an available Subject and enabled module. Archive/deletion faults Running processes while retaining history; an explicitly suspended process keeps its pause and any original fault. Disabling/enabling Workflow retains explicit suspension. Action hints (CanSuspend, CanResume, CanCancel, CanRetry) reflect current eligibility, which each command rechecks.

Definition facades expose GetSecurityAsync and UpdateSecurityAsync. HTTP uses GET/PUT workflow-definitions/{id}/security under the configuration base route. Assignments use Definition RowVersion, OperationId and audit, independently of YAML. Remove assignments before deleting a referenced role/group. Direct user assignments are not supported.

The runtime executes Start, Delay, User Input, DevLog, If, Wait Event and End. The Workflow instances list, preview and details share the administration controls; the execution diagram retains current visits while showing suspension.

Each runtime start assigns a stable WorkflowInstance.Number, such as WF-123. The numeric suffix comes from one sequence shared by all Workflow Definitions in the workspace. The Definition’s NumberPrefix defaults to WF-, allows an empty string, and accepts up to 32 characters. Create and update configuration requests expose this field; omitting it from an update preserves the current prefix. Changes apply only to future instances.

Replay and technical Retry preserve the number. A new start gets a new suffix; gaps are expected when a transaction rolls back. Direct EF writers must provide a unique complete Number. Do not include the presentation-only # in storage.

Runtime query snapshots include Number, DefinitionName, RevisionNumber and OutcomeName. Subject is a resource identity returned only when the caller can view the record. Runtime administrators without record access receive the technical projection. The WebApp opens an instance at /workflow/workflow-instances/{id} without requiring configuration permissions.

GeneratedWorkspaceContext exposes all Workflow tables, including WorkflowDefinitions, WorkflowRevisions, WorkflowRevisionContents, WorkflowOutcomes, WorkflowRevisionOutcomeReferences, WorkflowModuleSettings, WorkflowWorkspaceRoleAssociations, WorkflowDefinitionCommandReceipts, WorkflowInstances, WorkflowNodeInstances, WorkflowInstanceHistory, WorkflowRuntimeCommands and WorkflowDefinitionRuntimeAdministrators. The model also registers WorkflowObservation, WorkflowObservationSource and WorkflowObservationReceipt; these internal execution records are accessed with db.Set<T>(), not named generated DbSet properties. Prefer runtime queries over reading observation internals. The EF types are in Moltaro.Package.NET.Workflow.Schema and are already registered by the generated workspace context.

For example, a function with an injected GeneratedWorkspaceContext db can read unfinished process state:

using Microsoft.EntityFrameworkCore;
using Moltaro.Workflow.Engine.Runtime;
var instances = await db.WorkflowInstances.AsNoTracking()
.Where(row => row.WorkflowDefinitionId == definitionId
&& row.SubjectObjectId == subjectId
&& (row.Status == WorkflowInstanceStatusEnum.Running
|| row.Status == WorkflowInstanceStatusEnum.Faulted
|| row.Status == WorkflowInstanceStatusEnum.Suspended))
.ToListAsync(cancellationToken);

Direct EF writes use normal Add, property assignment and SaveChangesAsync. They do not execute a Workflow command, check Subject authorization or published revision admission, append history, or send notifications. Use a transaction for related state/history writes and replace RowVersion on updates to detect stale writers. Configuration services are a separate level with their existing checks. Direct history writers must lock the instance and advance LastHistorySequence in the same transaction as the history insert; allocated positions must never be reused. Prefer runtime commands for business transitions.

An instance pins a revision and stores the Subject object’s id; the Definition owns its type. Running, Faulted and Suspended reserve the Definition/Subject pair across revisions, so another unfinished instance is rejected by the database. Completed and Canceled release that pair. A technically completed process has an explicit business outcome, including failed or canceled business outcomes. Each node visit has a distinct id, supporting repeated visits. Fork/join is not supported. Runtime times are UTC DateTimeOffset; process values, visit results and event details use JSONB.

Wait Until appears as one waitUntil visit with WaitKind = Event, an optional fixed TimerDueAtUtc, and final OutputKey of satisfied or timeout. SQL checks read current persisted state using the same actor-independent evaluator as If. Events arriving between checking and waiting remain eligible; internal false checks do not create additional visits or ordinary history entries.

WorkflowNodeSnapshot.EventProgress and WorkflowExecutionVisit.EventProgress contain MatchedObservations and TotalObservations for an active event wait. They expose no observed record identities or field values and are omitted from technical-only projections without Subject View. Runtime services and HTTP use the same projection. Workflow SDK 7.1.0 references Engine 5.2.0; YAML remains v2.

One Move visit freezes its selection before effects and processes one card per continuation. Board movement, history/events, durable operation receipt and Workflow progress commit together under the instance fence. Business refusals are retained while remaining cards continue; technical errors retry the same pending attempt. Suspend retains progress; Cancel leaves completed moves in place.

Read GET instances/{id}/node-instances/{visitId}/board-move?page=1&pageSize=25 under the Workflow runtime route, or use SDK GetBoardMoveResultAsync. Subject View is required. Items and VisibleCount reflect the reader’s current SQL permissions before pagination. Progress is nullable when any source/card dependency is hidden. Do not infer executed totals from an empty visible page. OutputKey is the persisted Success/Failure decision, independent of visibility. No target Entity fields are granted by Board Item View.

Boards SDK ExecuteMoveOperationAsync accepts a stable operation id and exact Board pass. Same actor/payload replays a committed result after current View; changed payload conflicts. It does not grant System execution to ordinary clients.