Skip to content
bitzorcas
中EN

Guide

独立嵌入 Workflow Engine

在非 BitzOrcas Host 中组合工作流引擎,正确实现持久化、查询、权限、参与人、服务任务、通知、Timer、缓存与运维。

Last updated

Workflow Engine 可脱离 ASP.NET Core 和 Platform 模块运行,但不是开箱即用的数据库产品。宿主必须提供 IPersistenceStore、事务、Schema、租户边界和表达式求值器;可选端口缺失时有明确降级。

独立 Host 组合根

Workflow.Engine

IPersistenceStore

IExpressionEvaluator

IFlowDataPermissionChecker

IWorkflowQueryStore

通知 / 参与人 / 服务任务端口

租户隔离数据库

Persistence 与 ExpressionEvaluator 是构建硬依赖;权限、查询、通知、参与人和服务任务虽然属于可选端口,却分别影响 fail-closed 写入、查询效率、消息送达、任务分配与自动节点。生产宿主必须把“可构建”和“可运营”分开验收。

1. 包边界

包用途
BitzOrcas.Workflow.Abstractions定义、运行模型和所有端口
BitzOrcas.Workflow.Engine编译、节点行为、运行与服务实现
BitzOrcas.Workflow.DependencyInjectionIServiceCollection 组合
BitzOrcas.Workflow.FusionCache可选 L1/L2 缓存
BitzOrcas Infrastructure adaptersEF Core/SqlSugar 写 Store 与 QueryStore

不要让独立业务代码引用 Platform.Workflow.Application,除非也要采用 BitzOrcas 的 CurrentUser、Mediator、授权与 Endpoint。

2. 直接 Builder

最小可构建引擎
var engine = new WorkflowEngineBuilder()
// ① 必需:负责全部工作流表、事务和乐观并发。
.UsePersistence(persistenceStore)
// ② 必需:内置安全表达式求值器。
.UseExpressionEvaluator(new DefaultExpressionEvaluator())
// ③ 用户交互生产环境强烈要求;缺失时 fail-closed。
.UseFlowDataPermissionChecker(permissionChecker)
.Build();
IWorkflowTransitionFlow transitions = engine.RuntimeTransition;
ITaskService tasks = engine.Tasks;

Builder 若缺少 Persistence 或 ExpressionEvaluator 会抛 InvalidOperationException。Noop cache、无 QueryStore、无通知、无参与人 Provider 都允许构建,但能力会降级。

3. DI 组合

IServiceCollection 组合
// 写 Store 与读 Store 分离注册,二者必须共享租户语义。
services.AddScoped<IPersistenceStore, TenantAwareWorkflowStore>();
services.AddScoped<IWorkflowQueryStore, WorkflowReadStore>();
services.AddScoped<IFlowDataPermissionChecker, WorkflowPermissionChecker>();
services.AddScoped<IParticipantProvider, DirectoryParticipantProvider>();
services.AddScoped<INotificationChannel, DurableWorkflowNotificationChannel>();
services.AddScoped<IServiceTaskHandler, ApplicationServiceTaskHandler>();
// AddWorkflowEngine 负责引擎服务图,不会替宿主创建 Schema。
services.AddWorkflowEngine(options =>
{
options.Configuration = new WorkflowEngineConfiguration();
});

AddWorkflowEngine 注册 IWorkflowEngine 为 Scoped,避免捕获 Scoped DbContext。它会使用默认表达式求值器,并把聚焦端口分别转发到引擎。

注意:WorkflowEngineConfiguration 属性当前没有运行时消费;不要依赖 EnableHistory=false 等开关。

4. IPersistenceStore 合同

Store 不只是 CRUD。它必须保证:

  • BeginTransaction 覆盖同一操作的多表写;
  • Instance/Task 更新使用 expectedVersion;
  • Tenant filter 对所有读写一致;
  • Definition、Deployment、Instance、Execution、Task、Candidate、Activity、Timer、History、Statistics 的语义完整;
  • 取消令牌传递;
  • 唯一冲突和并发异常映射到 Engine 可识别类型;
  • 时间使用 UTC DateTimeOffset;
  • 查询排序稳定。

只实现“让接口编译”会产生静默错误。优先复用官方 Adapter 并运行 parity tests。

5. QueryStore

没有 IWorkflowQueryStore:

  • 简单待办可回退 IPersistenceStore;
  • 已办总数可能全量扫描;
  • 报表多返回空;
  • 统计预聚合没有原始数据。

生产宿主应实现数据库端 Assigned/Candidate UNION、租户谓词、count/page、报表范围查询。DataScope 高级过滤当前仍需框架改造,不能由宿主文档假定已下推。

6. 参与人和权限

IParticipantProvider 展开角色/岗位/组织;IParticipantResolver 处理自定义规则。两者都必须限定当前租户,返回稳定去重 UserId。

IFlowDataPermissionChecker 是运行红线。View、Operate、Manage 应分别映射到宿主授权系统,且 userId/tenantId 必须来自可信调用上下文。缺失 checker 时任务详情和写操作 fail-closed,这是安全默认值。

7. ServiceTask

ServiceTaskBehavior 调用 IServiceTaskHandler。Implementation 是 DSL 字符串,宿主应把它映射到 allowlist handler key,不执行任意反射或脚本。

受控服务任务
public Task HandleAsync(
string implementation,
IExecutionContext context,
CancellationToken cancellationToken)
{
// implementation 只能映射到受控白名单,不能反射执行任意类型。
return implementation switch
{
"matter.reserve-case-number" =>
reserveCaseNumber.ExecuteAsync(context, cancellationToken),
"conflict.register-waiver" =>
registerWaiver.ExecuteAsync(context, cancellationToken),
// 未知 key 必须明确失败并进入运维告警。
_ => throw new InvalidOperationException(
$"Unsupported service task: {implementation}")
};
}

外部调用必须有幂等键、超时、重试和补偿;不要把数据库事务跨网络保持。

8. 通知和业务回调

INotificationChannel 可选;缺失时流程不发通知。自建 Channel 应对齐平台适配器的契约——逐接收人持久化站内信与 Outbox 事实,任一失败计数后抛出异常——因为引擎侧的分发器现在会把异常向上重抛、令流转失败回滚,半途吞掉异常等于伪造成功。直接 Builder 可以接模板与偏好 Store,DI 扩展当前不会自动转发这两个端口。

IBusinessIntegrationCallback 失败语义要特别设计,因为它不是 Outbox。建议回调只写本地可靠 intent,异步更新业务系统。

9. Timer

IJobScheduler 负责创建调度记录;IWorkflowTimerProcessor/TimerJobHandler 负责扫描。独立宿主需要:

  • 每个 Job 的可信租户作用域;
  • 原子 Claim/lease;
  • attempt、backoff、DLQ;
  • 多实例互斥;
  • Reminder 的通知渠道;
  • Escalation/Transfer 的系统权限;
  • crash/restart 演练。

官方当前 Timer 先 Fired 后动作,嵌入方不能直接宣称可靠超时。

10. 缓存

默认 Noop 最简单且正确。引入缓存后,定义、部署和待办计数失效成为业务正确性的一部分。FusionCache 无 Redis 时只是进程内 L1;多节点需要 distributed cache + backplane,并验证故障降级。

11. 健康与观测

Readiness 检查数据库/Schema、QueryStore、租户上下文和必要端口;Timer/通知可作为独立组件状态。Metrics 覆盖命令延迟、冲突、任务年龄、Timer lag、通知 intent backlog、报表扫描与缓存。

日志包含 definitionId/instanceId/taskId 时要按敏感标识治理;Variables、Comment、BusinessKey 默认不得完整输出。

12. 独立宿主验收

  • 官方 Workflow unit 与 contract tests 通过;
  • 自定义 Store parity tests 覆盖事务、并发、租户和所有表;
  • 无 QueryStore 的降级被显式阻止或记录;
  • 自定义参与人/权限有跨租户拒绝测试;
  • ServiceTask 重放安全;
  • Timer crash window 与重试可恢复;
  • 通知与业务回调有持久 intent;
  • Schema migration、备份、恢复、归档和清理 Runbook 可执行。

13. 验证命令

Terminal window
dotnet test tests/BitzOrcas.Workflow.Tests/BitzOrcas.Workflow.Tests.csproj
dotnet test tests/BitzOrcas.Workflow.Integration.Tests/BitzOrcas.Workflow.Integration.Tests.csproj
rg -n "class .*PersistenceStore|IWorkflowQueryStore" src/Framework tests -g '*.cs' --glob '!**/bin/**' --glob '!**/obj/**'

返回工作流说明书

100%

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