流程定义是 JSON DSL,不是 BPMN XML。DefinitionCompiler 用 System.Text.Json 反序列化,属性名大小写不敏感,枚举采用 camelCase。部署后保存原始 JSON、版本、租户和 SHA-256 Checksum;运行实例只引用不可变快照。
这条流水线刻意把“部署定义”和“让新实例使用定义”分开。前者生成版本快照,后者修改租户/办公室绑定;只有模拟通过并不能替代真实持久化、并发与权限测试。
1. 七种内置节点
| type | 语义 | 关键配置 |
|---|---|---|
| startEvent | 唯一入口 | name、nodePrefix |
| endEvent | 终点,可多个 | name |
| userTask | 人工任务并挂起 Execution | participants、multiInstance、rollback、config |
| serviceTask | 宿主自动处理 | implementation、IServiceTaskHandler |
| exclusiveGateway | 第一条满足条件的分支 | Edge.condition、sort |
| parallelGateway | 所有分支并行/按父执行汇聚 | 无条件出线 |
| inclusiveGateway | 满足条件的多分支 | 条件与汇聚范围 |
2. 可部署的最小审批定义
{ "key": "matter-intake-approval", "name": "案件立案审批", "variables": { "disputeAmount": 0, "crossBorder": false }, "nodes": [ { "id": "start", "type": "startEvent", "name": "提交", "nodePrefix": "A" }, { "id": "partner", "type": "userTask", "name": "主办合伙人审批", "nodePrefix": "B", "participants": { "roles": ["litigation-partner"], "positions": [], "orgUnits": [], "userIds": [], "virtualRoles": [] }, "config": { "requireComment": true, "allowAddParticipant": true, "allowTransfer": true, "allowDelegate": true, "quickReplies": ["同意立案", "请补充利冲核查"] } }, { "id": "end", "type": "endEvent", "name": "完成" } ], "edges": [ { "source": "start", "target": "partner", "sort": 0 }, { "source": "partner", "target": "end", "sort": 0 } ]}注意:DefinitionCompiler 只验证基本可反序列化条件;真正的图校验由 ValidateDefinitionAsync 执行。DeployAsync 当前不会显式调用 DefinitionValidator,只要 JSON 可解析就可能保存,因此生产发布必须先调用 validate。
3. 条件表达式
默认求值器只支持变量、字符串/数值/布尔值、比较运算符和 AND/OR。它不执行方法、任意脚本、SQL 或对象属性导航。
{ "nodes": [{ "id": "route", "type": "exclusiveGateway", "name": "案件分级" }], "edges": [ { "source": "route", "target": "committee", "condition": "${disputeAmount >= 1000000 && crossBorder == true}", "sort": 10 }, { "source": "route", "target": "partner", "sort": 99 } ]}无条件边是默认分支,最多一条。字符串比较使用单引号或双引号。复杂业务条件应预先在业务层计算成稳定变量(例如”是否触 investor-state 仲裁条款”),避免把领域规则塞进 DSL。
4. 参与人
ParticipantRule 支持 Roles、Positions、OrgUnits、UserIds、VirtualRoles 和 Resolver。显式 Resolver 命中已注册 IParticipantResolver 后仍会合并 UserIds;未指定时使用 IParticipantProvider 展开角色、岗位与组织。
如果最终没有审批人,UserTaskBehavior 当前会自动 Leave,等价于自动通过,而不是失败或进入异常队列。关键审批节点必须在发布前用真实目录数据做“零审批人”测试,并考虑将该行为改为可配置 fail-closed。
5. 多实例
Parallel 为每个参与人创建并行任务;Sequential 逐个创建。CompletionCondition 可读取 nrOfInstances、nrOfCompletedInstances 与 nrOfActiveInstances。
{ "id": "conflict-committee", "type": "userTask", "name": "利冲审查委员会", "participants": { "userIds": ["101", "102", "103"] }, "multiInstance": { "mode": "parallel", "completionCondition": "${nrOfCompletedInstances >= 2}" }}条件满足后 MultiInstanceCompletionHandler 负责收口剩余任务。必须测试同时完成、最后一票竞争、取消兄弟任务、变量合并和并行网关嵌套。
6. 回退、任务配置与 DataScope
RollbackRule 支持 start、prev、selected 和 Targets;Reject 时显式 targetNodeId 可覆盖配置。UserTaskConfig 声明意见必填、快速回复、自动提交、加签/转办/委派开关、撤回时限和抄送。
FlowDataScopeConfig 是设计模型;平台当前真正的 View/Operate/Manage 决策来自 IFlowDataPermissionChecker。节点 DSL 规则没有直接传入 Platform checker,不能把它描述为已执行的行级 DSL。
7. 定时器
TimerConfig 接受 ISO 8601 duration,以及 remind、escalate、transfer 动作。UserTask 创建时由 IJobScheduler 安排 TimerJob;JobHost 的 workflow-timer 作业默认每 5 分钟扫描(BackgroundJobs:workflow-timer:IntervalSeconds 可覆盖),其执行作用域已注入 INotificationChannel → WorkflowNotificationAdapter,催办通知与 Fired 状态原子提交。
{ "timers": [ { "type": "boundary", "duration": "P2D", "action": "escalate", "escalateTo": "managing-partner" } ]}Timer 可靠性仍是已知薄弱面:先 Save Fired 再执行动作,进程在两步之间崩溃时记录不会自动回到 Pending,也没有跨实例 Claim/lease。定义作者可以把 Timer 用于提醒与升级,但不应将其当作强 SLA 承诺。
8. 节点监听器
listener type 支持 expression、notification、callback。NodeListenerDispatcher 对单个失败记录日志后重抛——监听器已按事务语义参与流程正确性,不再被静默隔离;expression 只 EvaluateVariable,不改变变量;notification 从特殊变量 __listenerRecipients 取接收人;callback 复用业务状态回调。
关键业务事实因此不应再完全依赖这条路径兜底:监听器抛出的异常会让整个流转命令失败,定义作者必须确保每个 listener 的实现具备与主事务匹配的可靠性。
9. 校验与模拟
Validator 检查节点 ID、悬空边、自环、单一开始、结束节点、入出线、网关条件、用户任务参与人和从开始节点可达性。不可达仅是 warning;它没有验证所有 Timer action、配置开关或表达式静态类型。
Simulator 最大深度 100,UserTask 即停止;排他/包容网关都只展示第一条命中路径,并行网关也只取第一条。因此模拟是设计预览,不是覆盖率证明。
DefinitionValidationResult validation = await repository.ValidateDefinitionAsync(json, cancellationToken);
// Error issue 阻断发布;可达性 warning 仍需留下明确评审结论。if (!validation.IsValid) return RejectWithIssues(validation.Issues);
Result<SimulationResult> simulation = await repository.SimulateAsync( json, new Dictionary<string, object?> { ["disputeAmount"] = 1200000m, ["crossBorder"] = true }, cancellationToken);
// 模拟通过后仍需真实持久化与并发集成测试。return await repository.DeployAsync( "matter-intake-approval", "案件立案审批", json, currentUserId, tenantId, cancellationToken);10. 业务绑定与可视化创作
定义根现在可声明 businessBinding.entityName,UserTask 可声明 formFields。可绑定实体与字段来自编译期 [BitzWorkflow]、[BitzFlowScope] 元数据,而不是浏览器手写目录。formFields 当前只有 fieldName 与 visibility,其中 visibility 为 editable、readOnly 或 hidden;字段必填性来自 FlowScope 元数据,不应写成 DSL 的 required 属性。
前端全页设计器使用服务端 designer-schema 和业务元数据目录,草稿以 Revision 做乐观并发。它的 /draft/publish 路径会重新执行权威校验;遗留 POST /api/workflow/definitions/ 仍只要求 JSON 可编译。完整接口、权限、版本作用域和浏览器恢复边界见可视化设计器。
11. 发布检查
- Key 与业务用途稳定,不复用为不同流程。
- 每个 UserTask 在真实租户都能解析审批人。
- 默认分支、空变量、数值/字符串类型均有测试。
- 并行/包容汇聚无死锁或提前结束。
- 变量不含秘密、超大对象或不可序列化类型。
- DefinitionId 对应的 JSON 被纳入变更评审与制品证据。
- validate、simulate 和 integration test 都通过。
从 BitzOrcas 五表或 Saury 步骤树生成这份 DSL 时,使用 Workflow Migrator。工具只产出结构与 sidecar 状态对照,不实现业务回调。