Skip to content
bitzorcas
中EN

Guide

运行工作流实例

深入说明发起、完成、驳回、撤回、重提、交接、控制、多实例、事务、并发、回调和定时器失败语义。

Last updated

运行时不是“把 CurrentNodeId 改成下一个节点”。它同时维护实例版本、Execution Token、任务、候选人、FlowState、BusinessStatus、轨迹、Timer、缓存和外部回调。所有业务调用都应从聚焦端口或 Platform Command 进入。

1. 运行时端口

端口用例
IWorkflowTransitionFlowStart、Complete、Reject、Withdraw、Resubmit
IWorkflowTaskHandoffFlowTransfer、Delegate、AddParticipant
IWorkflowMigrationFlowResetToNode、StartAtNode、TransferApplicant
IWorkflowBatchOperationTerminate、Cancel、Suspend、Resume、Remind、BatchComplete、Priority
IWorkflowQueryProgressView

IRuntimeService 仍组合全部方法,但已标为兼容门面。

2. 发起实例

TokenExecutorPersistenceRuntimeApplicationTokenExecutorPersistenceRuntimeApplicationStart(definitionKey, businessKey, trusted context)resolve Office/Tenant/Platform deploymentbuild instance + variables + serial contextbegin transactionsave instance and start activityexecute StartEvent and following nodescreate executions/tasks/timerscommitinstance snapshot
发起立案审批
// 操作者与租户都来自服务端认证上下文。
Result<IProcessInstance> started = await transitions.StartAsync(
definitionKey: "matter-intake-approval",
businessKey: matter.MatterNo,
businessType: "MatterIntake",
starterId: currentUserId,
tenantId: currentTenantId,
officeId: matter.OfficeId,
variables: new Dictionary<string, object?>
{
// 只传流程路由所需的最小快照,不传完整业务对象。
["disputeAmount"] = matter.DisputeAmount,
["crossBorder"] = matter.IsCrossBorder
},
cancellationToken);

当前 Start 接口没有 IdempotencyKey。虽然 Store 提供按 definitionKey+businessKey 查询实例,但 Start 流程没有在创建前显式检查;数据库是否有唯一约束必须另行证明。客户端超时后应先查业务关联,不能直接重试。

3. 完成任务

Complete 先加载 Pending Task,通过 Operate 数据权限,再加载实例与锁定定义。事务中推进实例 Version、完成任务、处理多实例、结束当前节点、移动 Token、更新 FlowState 和轨迹。提交后失效相关待办缓存。

审批通过并补充路由变量
// 完成任务前由引擎再次校验 Pending 状态与 Operate 权限。
Result completed = await transitions.CompleteTaskAsync(
taskId,
currentUserId,
comment: "利冲核查通过,同意立案",
variables: new Dictionary<string, object?>
{
["conflictCleared"] = true,
["engagementLetterSent"] = false
},
cancellationToken);
if (completed.IsFailure)
{
// TaskNotPending 可能表示另一请求已完成;ConcurrencyConflict 表示版本竞争。
return MapWorkflowFailure(completed.Error);
}

当前 HTTP Request 不带 task version 或幂等键。乐观锁保护数据库,但调用者无法获得同一请求的确定性重放结果。

4. 驳回、撤回与重提

Reject 可显式 targetNodeId,也可按 RollbackRule 解析目标;它取消/重建相关执行与任务并写轨迹。Withdraw 只允许当前申请人语义,Resubmit 在撤回/退回状态恢复流程。

申请人可能通过 IApplicantResolver 动态解析,失败时回退 CurrentApplicantId/StarterId 快照。TransferApplicant 更新当前申请人,后续撤回和通知使用新身份。

5. 转办、委派与加签

Transfer 永久改变任务责任;Delegate 表示临时委派;AddParticipant 增加审批人。这些操作在事务内先推进实例 Version,使纯任务写也参与同一并发边界。

转办任务
// successorUserId 应先通过同租户目录与在职状态校验。
Result transferred = await handoff.TransferTaskAsync(
taskId,
fromUserId: currentUserId,
toUserId: successorUserId,
comment: "休假期间转交",
cancellationToken);

UserTaskConfig 声明 AllowTransfer/AllowDelegate/AllowAddParticipant,但当前运行方法是否强制读取这些字段必须逐项核验;不能只靠前端隐藏按钮。

6. 控制操作

Suspend/Resume、Terminate/Cancel、Reset、Priority 都要求 Manage 数据权限并使用实例 Version。Terminate 与 Cancel 都是终态,但业务含义不同:Terminate 是管理者强制结束,Cancel 是业务取消。

BatchComplete 是特殊管理操作:它原子地把一组 Pending Task 标为 Completed,并推进相应实例 Version,却明确不触发流程推进。不要把它用作普通批量审批,否则实例仍停在原节点。

Remind 解析当前 Pending Assignee 并分发 TaskRemind;通知失败会随命令一起失败回滚(见第 8 节),催办不再可能”悄悄丢失”。

7. 多实例与网关

并行多实例为每位参与人创建任务,CompletionCondition 决定何时收口;顺序多实例逐个创建。ParallelGateway 依赖父子 Execution 判断汇聚,InclusiveGateway 选择满足条件的分支。

必须覆盖:

  • 两个审批人同时提交最后一票;
  • CompletionCondition 恰好跨阈值;
  • 兄弟任务取消与缓存失效;
  • 并行分支变量合并;
  • 嵌套并行的 parentId 范围;
  • 包容网关零条件命中与默认边。

8. 事务与外部副作用

多表写由 IPersistenceStore.BeginTransactionAsync 包裹;引擎把 DB 并发异常规范化。通知与监听器已并入失败链条:平台 INotificationChannel 逐接收人写站内信与 CAP Outbox,任一失败计数后抛出;NotificationDispatcher 记录日志后重抛;EventDispatcher 同样向上传播监听器异常——整个流转命令因此失败回滚。审批成功与”通知事实已落库”现在是同一个命题。

IBusinessIntegrationCallback 由运行时直接调用,并非持久 Outbox。不同用例的调用点可能在事务之后;回调失败可能让请求失败或留下状态已提交的窗口。业务状态同步应具备幂等、重放和对账。

9. 定时器

进入带 Timers 的节点后调度 TimerJob;JobHost 周期扫描 Pending。当前处理顺序是先 Save Fired,再 Dispatch:

当前 Timer 失败窗口
var fired = job with { Status = "Fired" };
await store.SaveTimerJobAsync(fired, cancellationToken);
// 这里进程崩溃或动作失败,记录不会自动回到 Pending。
await DispatchJobAsync(job, cancellationToken);

扫描也没有原子 Claim;多实例 JobHost 可能同时读到同一 Pending。必须新增状态 CAS/lease、attempt、nextRetryAt、lastError、死信与恢复 Runbook。

10. 错误处理

Result 错误映射到 ProblemDetails。调用方应区分 NotFound、Forbidden、InvalidState、TaskNotPending、ConcurrencyConflict 和基础设施异常。不要把所有 409 自动重试;并发冲突通常要求重新读取用户意图。

11. 测试清单

  • Start 的业务键重复与客户端断线重试;
  • 双 ORM 的原子多表写和 rollback;
  • 完成/驳回/终止竞争;
  • 当前用户、候选人与 Manage 权限;
  • 通知/回调失败时数据库事实;
  • Timer 重复扫描、崩溃、未知类型、动作失败;
  • 多实例和并行网关;
  • 缓存失效及多 API 节点一致性。

下一篇:任务管理

100%

滚轮或按钮缩放 · 放大后拖动画面 · 双击切换 100% / 200%