3. 流程引擎核心原理
流程引擎的本质,是把一张静态的流程定义图变成可运行、可暂停、可恢复、可追溯的运行时状态机。理解引擎,不能只记住“节点会往下走”,而要抓住一条主线:令牌(Token)在流程图上移动,每进入一个活动就产生一个活动实例,活动实例按执行语义完成或等待,网关决定令牌如何分叉与汇聚,事件订阅让等待中的实例被外部消息唤醒,补偿与事务边界保证出错时能回退,持久化与恢复策略保证引擎重启后状态不丢。下面按这条主线展开。
令牌推进:引擎的“执行指针”
令牌是流程实例中表示“当前执行位置”的逻辑标记。一个流程实例启动时,在开始事件处生成一个令牌;令牌沿顺序流前进,进入活动节点后触发该活动的执行。若活动是自动任务(如服务任务),引擎执行完立即让令牌沿出口顺序流继续;若活动是等待型任务(如用户任务、接收任务),令牌会停在活动实例上,直到外部条件满足才继续。
需要区分两类推进语义:单令牌顺序推进与多令牌并行推进。并行网关会为每条出口分支各生成一个令牌,形成多个活动实例同时存在;汇聚网关则等待所有入分支令牌到达后才合并为一个令牌继续。令牌数量与活动实例数量并不总是一一对应,例如多实例活动会为每个集合元素生成一个实例,但可能共享同一令牌上下文。
活动实例与执行语义
活动实例是令牌进入活动节点后产生的运行时对象,记录活动定义、所属流程实例、当前状态(激活、等待、完成、取消、补偿中)、输入输出变量、开始与结束时间。执行语义决定活动实例如何被驱动:
- 自动执行:服务任务、脚本任务在令牌到达时同步或异步执行,执行完自动离开。
- 等待执行:用户任务、接收任务、定时器任务会创建等待状态,令牌停在实例上,等待任务完成、消息到达或定时触发。
- 多实例执行:对集合逐项创建实例,可串行或并行,需定义完成条件(全部完成、任一完成或达到阈值)。
- 子流程执行:内嵌子流程在父实例内展开令牌;调用活动则启动独立流程实例,通过调用关系关联。
执行语义还涉及变量作用域:流程实例级变量全局可见,活动实例级变量仅在本活动及子活动内可见。变量在网关条件、任务表单、服务任务参数中被读取,写入时需注意并发覆盖问题。
网关路由:条件、并行与事件
网关是令牌的分流与合流控制器,常见类型包括:
- 排他网关:按顺序评估出口条件,选择第一条为真的分支,只产生一个令牌,适合互斥决策。
- 并行网关:无条件为每条出口生成令牌,汇聚时等待所有入分支到达,适合必须同时进行的任务。
- 包容网关:可同时激活多条满足条件的分支,汇聚时等待已激活分支全部到达,兼顾条件与并行。
- 事件网关:后续接多个捕获事件,哪个事件先发生就走哪条分支,其余事件订阅取消,适合超时与消息竞争场景。
路由正确性依赖条件表达式的确定性。例如排他网关出口条件应互斥且覆盖完整,否则可能出现无分支可选导致流程卡死,或多分支同时为真导致非预期路径。并行网关汇聚必须与分叉配对,否则令牌可能永久等待。
事件订阅:等待中的唤醒机制
当令牌停在等待型活动上,引擎会为该活动实例注册事件订阅。事件订阅是“等待什么”的声明,常见类型有消息订阅、信号订阅、定时器订阅、条件订阅。外部系统发送消息、定时器到期或条件满足时,引擎查找匹配的订阅,将令牌从等待活动推进到下一节点。
事件订阅需要处理竞争与取消:事件网关中多个订阅同时存在,一旦某个事件触发,其余订阅必须取消,避免重复推进;边界事件附着在活动上,活动完成或取消时边界事件订阅也应清理。订阅未清理会造成“幽灵唤醒”,即流程已离开该活动却仍被旧消息推进。
补偿与事务边界
流程执行中,已完成的业务活动可能需要回退。补偿事件用于对已成功完成的活动执行反向操作,例如“扣款”成功后若后续“发货”失败,则触发“退款”补偿。补偿通常由补偿边界事件或补偿抛出事件触发,引擎按完成顺序逆序执行补偿处理器。
事务边界用于界定一组活动要么全部成功、要么全部补偿。事务子流程内任一活动失败,可触发取消结束事件,引擎取消事务内所有活动实例并执行补偿。需要注意:补偿不是数据库回滚,而是业务级反向操作,必须显式定义补偿处理器,且补偿本身也可能失败,需要幂等设计。
持久化与恢复策略
流程引擎必须持久化运行时状态,否则重启后无法恢复。持久化对象包括流程实例、活动实例、令牌位置、变量、事件订阅、定时器作业、作业重试记录。持久化时机通常在令牌推进前后、活动实例状态变更时、事件订阅注册与取消时。
恢复策略关注引擎重启后如何继续:
- 作业恢复:定时器作业、异步任务在重启后由作业执行器重新调度,需处理重复触发与错过触发。
- 令牌恢复:根据持久化的活动实例与令牌位置,重建等待状态,重新注册事件订阅。
- 一致性恢复:若持久化与业务操作不在同一事务,需通过补偿或对账修复不一致。
下面这张图把令牌推进、活动实例、网关路由、事件订阅、补偿与持久化的关系放在同一张运行时视图里,便于对照理解。
把这张图记牢,再回头看引擎的配置与代码,就能把“节点、连线、变量、订阅、作业、事务”这些分散概念串成一条可运行的链路。实际工程中,建议在流程定义阶段就明确每个等待活动的订阅类型与超时策略,在网关处校验条件互斥性,在事务边界内显式声明补偿处理器,并为持久化与恢复设计对账机制。这样,流程引擎才能在异常、重启与并发场景下保持状态一致、可恢复、可追溯。