Skip to content
bitzorcas
中EN

Concept

Workflow Architecture and Core Concepts

Deep guide to layers, focused ports, execution model, command/query stores, transactions, concurrency, cache, tenancy, and host composition.

Last updated

Workflow separates engine semantics from product integration. Framework knows definitions, runtime objects, and ports. Platform.Workflow connects current identity, common authorization, platform notifications, and endpoints. Infrastructure selects the database. Each Host decides whether and where to run it.

1. Dependency direction

API Host / JobHost

Platform.Workflow.Application

Composition roots

Workflow.Abstractions

Platform Authorization / Notifications

Workflow.Engine

Workflow.DependencyInjection

Workflow.FusionCache

Infrastructure.EfCore

Infrastructure.SqlSugar

Dapper query adapter

Engine references neither Platform, Host, EF Core, SqlSugar, nor Dapper. Abstractions still references Domain and Persistence.Metadata for result and compile-time persistence contracts; ORM-neutral does not mean framework-free.

2. Core models

ModelResponsibility
WorkflowDefinitionimmutable JSON snapshot with nodes, edges, variables, checksum
WorkflowDeploymenttenant+office binding to active and previous definitions
ProcessInstance / Executionbusiness snapshot and token position
WorkflowTask / ActivityRecord / TimerJobhuman work, evidence, and due action

Changing only CurrentNodeId corrupts Execution, Task, FlowState, trail, timer, and cache consistency.

3. Focused service ports

IWorkflowEngine

Repository

TransitionFlow

TaskHandoffFlow

MigrationFlow

BatchOperation

RuntimeQuery

TaskService

HistoryQuery

ArchivePort

AnalyticsPort

ManagementService

Transition advances primary state. Handoff changes task responsibility. Migration starts at a node and transfers applicants. BatchOperation handles terminate, cancel, suspend, reminder, proxy completion, and priority. Compatibility facades remain, but should not grow.

4. Command and query stores

IPersistenceStore covers definitions, bindings, instances, executions, tasks, candidates, activity, timers, history, and statistics. IWorkflowQueryStore covers database todo paging, timelines, and report source sets.

5. Completion transaction

EventDispatcherPersistenceRuntimeTransitionApplication handlerEventDispatcherPersistenceRuntimeTransitionApplication handlerCompleteTaskload task, instance, definitionpermission and state checksbegin transactionadvance instance Versioncomplete task, resume execution, move tokenupdate state and trailcommitcallback and lifecycle notificationlistener failures logged and rethrown

Exact callback placement varies by operation. Review the relevant WorkflowRuntimeCore partial file before making atomicity claims.

Notification and listener failure semantics deserve emphasis: the platform INotificationChannel writes per-recipient inbox entries plus CAP Outbox rows, counts any recipient failure, and throws at the end; the dispatcher logs and rethrows, and EventDispatcher propagates listener exceptions upward. A commit therefore either succeeds together with the notification facts or fails as a whole — “the flow succeeded but notifications silently vanished” is no longer a legal state. The trade-off: a broken notification channel blocks approval actions themselves.

6. Optimistic concurrency

Instance Version is the shared write boundary. Handoff and proxy-completion operations advance it even when primarily changing tasks. EF Core sets OriginalValue; SqlSugar issues a version-qualified update. The engine maps known concurrency exceptions to ConcurrencyConflict.

Handle conflict without blind retry
Result result = await transitions.CompleteTaskAsync(
taskId,
currentUserId,
"Approved",
null,
cancellationToken);
// A conflict means the decision was based on stale task state.
if (result.IsFailure &&
result.Error.Code == "Workflow.Runtime.ConcurrencyConflict")
{
// Reload task and progress and ask the user to confirm current intent.
return Result.Failure("Workflow changed; refresh before retrying.");
}

Concurrency control is not idempotent response replay.

7. Cache

ExecutionGraphCache is local to the engine instance. IWorkflowCache stores definitions, deployment bindings, and todo counts; Noop is the default. Platform FusionCache always has L1 and adds Redis L2/backplane when the required services exist.

Invalidation is correctness-critical. Handoff, candidate refresh, and applicant transfer must invalidate every affected user’s view.

8. Tenancy

Deployment resolves exact office, tenant ALL, then PLATFORM/ALL. Platform handlers use CurrentUser tenant. JobHost resolves the parent instance tenant outside normal filters, establishes system identity and ORM filter scope, and then executes the timer.

Several history ports accept only businessKey or instanceId. Tenant isolation therefore depends on adapter context. Standalone adapters must enforce an equivalent predicate.

9. Host composition

API Host registers persistence first. AddBitzOrcasWorkflowEngine is a no-op without IPersistenceStore, and endpoint mapping is conditional on IWorkflowEngine.

JobHost registers the timer chain only when SqlSugar is present: WorkflowBackgroundJobsExtensions.AddWorkflowBackgroundJobs wires SqlSugarWorkflowPersistenceStore, a timer tenant execution scope, a system permission checker, and INotificationChannel → WorkflowNotificationAdapter — so background reminder notifications, business actions, Outbox rows, and Fired state commit atomically in one execution scope. The timer processor WorkflowTimerProcessor takes ILicenseGate as a required dependency and drives due timers, timeout escalation, and timeout transfer.

10. Inert configuration today

EnableHistory, EnableActivityRecord, EnableListeners, DefaultPriority, and EnableMultiTenancy are stored on Engine.Configuration but never read by runtime logic; setting these values does not change behavior. The workflow.runtime feature, by contrast, is enforced: WorkflowRuntimeLicenseGuard evaluates it via ILicenseGate before every workflow write and every background job (timer jobs, statistics aggregation), fail-closed.

11. Architecture evidence

  • Engine has no ORM or Platform reference.
  • Handlers depend on focused ports.
  • EF Core and SqlSugar implement the complete store contract.
  • Every update uses expectedVersion.
  • Generated metadata and tenant semantics match across providers.
  • API Shell does not create a half-composed engine.
  • Job tenant scope is restored after success and failure.

12. Source checks

Terminal window
rg -n "ProjectReference|PackageReference" src/Framework/BitzOrcas.Workflow/**/**.csproj
rg -n "ExecuteInTransactionAsync|ExecuteWithConcurrencyGuardAsync|expectedVersion" src/Framework/BitzOrcas.Workflow src/Framework/BitzOrcas.Infrastructure.* -g '*.cs'
rg -n "AddBitzOrcasWorkflowEngine|AddWorkflowBackgroundJobs|INotificationChannel" src/Hosts -g '*.cs'

Back to Workflow manual

100%

Scroll or use controls to zoom · drag when enlarged · double-click for 100% / 200%