跳转至

后端 LiteFlow 使用与开发规范

📄 创建: 李锦鹏 2026-08-17

https://doc.xpku.com/raw/products/process-engine/liteflow-doc.md

文档版本:1.0

适用范围:tpm-backend 中所有接入 LiteFlow 规则编排的业务模块,以及公共 SDK bams-flow 提供的 LiteFlow 封装能力。

本文以当前代码、规则 XML 和 bams-flow SDK 源码为准,说明 LiteFlow 的架构分层、核心概念、 编写规范、配置方式、规则发布与版本管理、事务并发以及故障排查方式。


1. 概述

TPM 后端使用 LiteFlow 承担「业务规则编排 / 状态机流转」职责,而审批工作流由 Warm-Flow 承担。两者统一封装在公共 SDK cn.cnbm.bams:bams-flow 中,宿主业务(如润滑计划、润滑工单)不直接依赖 LiteFlow 原生 API,而是通过 SDK 暴露的 版本化执行器、模板服务、链查找服务、实例仓库类型化节点基类 完成业务流转。

核心特征:

  1. 多工厂、多模板、多版本:同一套规则模板可为不同工厂发布不同版本,版本不可变。
  2. 规则数据库化:规则 XML 统一保存在 sys_liteflow 表,ACTIVE 记录是当前版本的唯一数据源, 不再使用本地 XML 资源映射或 Redis current 指针。
  3. 固定版本实例:首次执行后业务表保存 instanceId,后续动作通过 Redis 实例恢复固定版本, 保证「流程进行中」不会因切换 ACTIVE 版本而中途改变规则。
  4. 业务状态由节点计算、事务服务统一落库:LiteFlow 节点只做「状态校验 + 状态迁移 + 变更意图输出」, 数据库提交由业务 FlowService 在 Spring 事务中原子完成。
  5. 乐观并发控制:数据库更新始终带「原状态」条件,避免并发请求互相覆盖。

2. 整体架构与依赖

2.1 依赖关系

tpm-backend-service
    └── cn.cnbm.bams:bams-flow            (SDK 封装层)
            ├── LiteFlow Starter          (com.yomahub.liteflow)
            ├── LiteFlow Redis Rule-DB Provider
            └── Warm-Flow Starter         (审批工作流,与本文关系较小)

tpm-backend-service/pom.xml 引入:

<dependency>
    <groupId>cn.cnbm.bams</groupId>
    <artifactId>bams-flow</artifactId>
</dependency>

SDK 源码位置(不在 tpm-backend 仓库内):

E:\java\zjc_git\bams\bams-sdk-apex\bams-flow

2.2 SDK 核心包结构

cn.cnbm.bams.flow
├── config
│   ├── BamsFlowProperties                    # bams.flow.* 配置
│   ├── LiteFlowRuleDbProperties              # liteflow.rule-db.* 配置
│   └── FlowAutoConfiguration                 # 按开关条件注册封装 Bean
├── lite
│   ├── entity
│   │   └── SysLiteFlow                       # sys_liteflow 表实体
│   ├── instance
│   │   ├── BamsLiteFlowInstance              # 业务实例元数据(归属 + 版本)
│   │   ├── BamsLiteFlowInstanceRepository    # 实例仓库 SPI
│   │   └── RedisBamsLiteFlowInstanceRepository # 默认 Redis 实现
│   ├── mapper
│   │   └── SysLiteFlowMapper                 # MyBatis-Plus Mapper
│   ├── node
│   │   ├── BamsTypedNodeComponent<C>         # 类型安全节点基类
│   │   ├── BamsHumanConfirmationContext      # 人工确认上下文契约
│   │   └── BamsHumanConfirmationNode         # 公共布尔节点 flowHumanConfirmation
│   ├── runtime
│   │   ├── BamsVersionedFlowRequest          # 一次版本化规则执行请求
│   │   ├── BamsVersionedFlowResult           # 一次版本化规则执行结果
│   │   ├── BamsVersionedLiteFlowExecutor     # 版本化执行器接口
│   │   ├── BamsVersionedLiteFlowExecutorImpl
│   │   ├── BamsLiteFlowChainService          # chain 查找 + Rule-DB 候选加载
│   │   └── BamsLiteFlowChainServiceImpl
│   └── service
│       ├── BamsLiteFlowService               # 原生 FlowExecutor 薄封装
│       ├── BamsLiteFlowTemplateService       # currentVersion / versionedChain
│       ├── BamsLiteFlowActiveTemplateService # ACTIVE 查询 / 激活
│       ├── BamsLiteFlowRulePublisherService  # 数据库 XML 发布 / 激活
│       └── SysLiteFlowService

2.3 业务侧包结构(tpm-backend-service)

cn.cnbm.bams.ems.service.flow
├── support
│   └── AbstractVersionedRuleFlowService<E, C, A>   # 版本化规则调用模板方法
├── constant
│   ├── EmLubricationPlanFlowConstants
│   └── EmLubricationOrderFlowConstants
└── lubrication
    ├── EmLubricationPlanFlowAction
    ├── EmLubricationPlanFlowCommand
    ├── EmLubricationPlanFlowService
    ├── EmLubricationOrderFlowAction
    ├── EmLubricationOrderFlowService
    ├── context
    │   ├── EmLubricationPlanFlowContext
    │   └── EmLubricationOrderFlowContext
    └── node
        ├── EmLubricationPlanFlowNodeSupport
        ├── EmLubricationPlanSubmitEffectiveNode
        ├── EmLubricationPlanSubmitForApprovalNode
        ├── EmLubricationPlanApproveNode
        ├── EmLubricationPlanRejectNode
        ├── EmLubricationPlanCompleteDispatchNode
        ├── EmLubricationOrderFlowNodeSupport
        ├── EmLubricationOrderCreateAssignedNode
        ├── EmLubricationOrderCreatePendingClaimNode
        ├── EmLubricationOrderClaimNode
        ├── EmLubricationOrderStartNode
        ├── EmLubricationOrderSubmitNode
        ├── EmLubricationOrderAcceptNode
        └── EmLubricationOrderRejectAcceptanceNode

3. 核心概念与术语

术语 含义 示例
规则模板 templateCode 某类业务的规则模板编码,全局稳定 lubrication-planlubrication-order
规则版本 version 模板的不可变版本,格式v[0-9]+ v1v3
基础 chain baseChainId XML 中未加任何后缀的 chain 名,业务代码只使用它 lubricationPlanCreate
版本化 chainId 基础 chain + 工厂 + 模板 + 版本拼出的最终 chain 见第 7 节
业务实例 instanceId 首次规则成功执行后由 LiteFlowrequestId 建立并持续沿用的 ID 1b810ee...
固定版本 实例绑定后不再改变的规则版本 首次绑定的v3
动作 action 业务语义上的一个流程操作,映射到一个基础 chain SUBMITAPPROVAL
上下文 context 单次规则执行的业务数据载体 EmLubricationPlanFlowContext
节点 node 一个@LiteflowComponent,只负责一条状态迁移 lubPlanApprove
定义链 definition chain 只描述状态顺序、不参与流转、供前端读取的 chain lubricationPlanDefinition
人工确认节点 SDK 提供的公共布尔节点,用于 IF 分支 flowHumanConfirmation

4. 配置规范

4.1 配置位置

tpm-backend-admin/src/main/resources/application.yml
docker/config/application.yml

两处应保持一致。

4.2 完整配置示例

bams:
  flow:
    # bams-flow 模块总开关
    enabled: true
    # 注册 Warm-Flow 审批流封装服务
    warm-flow-enabled: true
    # 注册 LiteFlow 规则编排封装服务
    lite-flow-enabled: true
    # 业务实例 Redis Key 前缀;完整 Key = 前缀 + templateCode + ":" + instanceId
    key: 'tpm:liteflow:instance:'

liteflow:
  # LiteFlow 引擎开关(由 LiteFlow Starter 读取)
  enable: true
  rule-db:
    # 是否启用 Redis Rule-DB 与数据库多版本发布能力
    enabled: true
    # 规则应用编码,必须与 sys_liteflow.app_code 一致
    application-name: tpm-admin
    redis:
      address: redis://${spring.data.redis.host}:${spring.data.redis.port:6379}
      username: ${spring.data.redis.username:}
      password: ${spring.data.redis.password:}
      database: ${spring.data.redis.database:0}
      key-prefix: bams-liteflow
      key-hash-tag: ${LITEFLOW_REDIS_KEY_HASH_TAG:}
    sync:
      poll-seconds: 3        # 增量变更轮询周期
      reconcile-seconds: 60  # 全量校准周期

4.3 配置项说明

配置项 默认值 含义
bams.flow.enabled true bams-flow 模块总开关,关闭后不注册封装 Bean
bams.flow.warm-flow-enabled true 是否注册BamsWarmFlowService
bams.flow.lite-flow-enabled true 是否注册BamsLiteFlowService 及公共人工确认节点
bams.flow.key bams:liteflow:instance: 业务实例 Redis Key 前缀
liteflow.enable LiteFlow 默认 LiteFlow 引擎开关
liteflow.rule-db.enabled false 是否启用 Rule-DB 及数据库多版本能力,必须显式 true
liteflow.rule-db.application-name spring.application.name,兜底 admin 应用隔离编码,同时用于查询sys_liteflow
liteflow.rule-db.redis.address Redis Publisher 地址
liteflow.rule-db.redis.key-prefix bams-liteflow 官方 Rule-DB 规则正文/索引/同步数据 Key 前缀
liteflow.rule-db.redis.key-hash-tag Redis Cluster 下统一 hash tag
liteflow.rule-db.sync.poll-seconds Provider 默认 增量变更轮询周期
liteflow.rule-db.sync.reconcile-seconds Provider 默认 全量校准周期

注意:bams.flow.key(业务实例 Key)与 liteflow.rule-db.redis.key-prefix (官方 Rule-DB Key)是两个不同命名空间,不要混淆。Redis 连接参数必须与 spring.data.redis.* 保持一致。


5. 数据库表结构

5.1 sys_liteflow(规则模板表)

DDL 由 bams-flow SDK 提供(db/migration/V1.6.0__sys_liteflow.sqlV1.6.1__remove_sys_liteflow_deleted.sql):

字段 类型 说明
id VARCHAR(20) 主键
app_code VARCHAR(64) 规则所属应用编码,与liteflow.rule-db.application-name 一致
corp_code VARCHAR(32) 工厂编码
template_code VARCHAR(64) 业务规则模板编码
version VARCHAR(32) 不可变版本,v[0-9]+
xml_content TEXT LiteFlow EL XML 原文
status VARCHAR(16) DRAFT / PUBLISHED / ACTIVE / DISABLED
publisher VARCHAR(20) 发布人
created_by / created_time / updated_by / updated_time 审计字段

约束:

UNIQUE KEY (app_code, corp_code, template_code, version)
KEY        (app_code, corp_code, template_code, status)

说明:sys_liteflow移除 deleted 逻辑删除字段,生命周期完全由 status 表达。 同一 app_code + corp_code + template_code 下同时只有一个 ACTIVE 版本。

5.2 业务表流程字段

以润滑计划 / 润滑工单为例,业务表需要新增:

字段 含义
plan_status / status 业务状态编码(如012...)
instance_id LiteFlow 首次执行建立的固定实例 ID
is_enabled (计划)启停标记,1 启用、0 停用
corp_code 工厂编码,用于选择规则模板版本

业务状态编码必须集中在状态枚举中,禁止散落字符串。


6. 业务状态枚举规范

6.1 润滑计划 EmLubricationPlanStatus

编码 枚举 名称 说明
0 DRAFT 编制中 初始状态,唯一允许编辑
1 REJECTED 已驳回 审批驳回,允许修改后重新提交
2 PENDING_APPROVAL 待审批 等待审批
3 PENDING_DISPATCH 待派工 审批通过后等待派工
4 EXECUTING 执行中 派工完成 / 直接生效的终态,isEnabled=1
5 DISABLED 已停用 人工停用(由服务在定义链解析后统一追加)

6.2 润滑工单 EmLubricationOrderStatus

编码 枚举 名称
0 PENDING_CLAIM 待领取
1 PENDING_LUBRICATION 待润滑
2 LUBRICATING 润滑中
3 PENDING_ACCEPTANCE 待验收
4 COMPLETED 已完成

6.3 枚举编写规范

  • 每个状态枚举同时定义 code(数据库值)与 displayName(中文名称)。
  • 提供 fromCode(String) 统一解析,非法编码抛 IllegalArgumentException
  • 禁止在业务代码中直接写状态字符串或数字。

7. 版本化 Chain ID 规则

版本化 chain ID 由 BamsLiteFlowTemplateService.versionedChain(...) 生成,分隔符固定为 双下划线 __(Redis Rule-DB 禁止冒号和空白)。

7.1 生成规则

场景 结果格式 示例
完整作用域 baseChainId__corpCode__templateCode__version lubricationPlanCreate__120101__lubrication-plan__v3
templateCode(历史实例) baseChainId__version lubricationPlanCreate__v3
corpCode(历史实例) baseChainId__templateCode__version lubricationPlanCreate__lubrication-plan__v3
version = legacy(XML 配置模式) baseChainId lubricationPlanCreate

7.2 校验规则

  • version 必须匹配 v[0-9]+
  • corpCode / templateCode / baseChainId 只能包含 [A-Za-z0-9_.-]+(不能有冒号、空白)。
  • 业务代码和 XML 只使用基础 chain 名,禁止手工拼接版本化 chain ID,统一由 SDK 生成。

8. 规则执行核心流程(模板方法)

SDK 的 BamsVersionedLiteFlowExecutorImpl.execute(...) 固定执行:

  1. 解析版本:无 instanceId → 取 currentVersion(ACTIVE);有 instanceId → 从 Redis 实例恢复固定版本并校验归属。
  2. 生成版本化 chain 并查找;不存在时:
  3. optionalChain=true → 返回 executed=false
  4. 否则抛 IllegalStateException
  5. 执行 chain,校验引擎 isSuccessrequestId
  6. 建立实例:首次用 requestId 作为 instanceId,后续沿用原实例,返回 BamsVersionedFlowResult

业务侧 AbstractVersionedRuleFlowServicetpm-backend)以模板方法固定调用顺序:

构造 BamsVersionedFlowRequest
  → executor.execute(request, context)
  → 若 executed=false → handleUnexecutedRule(...)   (仅可选链进入)
  → validateExecutionResult(...)                    (业务结果校验)
  → persistExecutionResult(...)                     (原子落库)
  → flowInstanceRepository.save(execution.instance())(保存固定版本实例)
  → afterExecution(...)                             (领域日志)

抽象方法 / 可覆盖钩子:

方法 必填 职责
getBusinessId(E) 业务主键
getFlowInstanceId(E) 已绑定实例 ID,首次为 null
getCorpCode(E) 工厂编码
getTemplateCode() 模板编码
getChainId(A) 动作 → 基础 chain
getActionDisplayName(A) 动作中文名(日志/异常)
validateExecutionResult(...) 校验节点是否产生合法状态变化
persistExecutionResult(...) 带原状态条件原子落库
isOptionalChain(A) 默认false
handleUnexecutedRule(...) 默认抛异常
afterExecution(...) 默认空实现

9. 业务 FlowService 编写规范

每个接入 LiteFlow 的业务需要提供一个 FlowService,继承 AbstractVersionedRuleFlowService<E, C, A>

9.1 结构模板

@Slf4j
@Service
public class XxxFlowService extends AbstractVersionedRuleFlowService<
        XxxEntity, XxxFlowContext, XxxFlowAction> {

    // 仅注入领域服务,公共执行器/实例仓库通过 super 传入
    public XxxFlowService(
            BamsVersionedLiteFlowExecutor versionedFlowExecutor,
            BamsLiteFlowInstanceRepository flowInstanceRepository,
            XxxService xxxService) {
        super(versionedFlowExecutor, flowInstanceRepository);
        this.xxxService = xxxService;
    }

    @Transactional(rollbackFor = Exception.class)
    public XxxEntity execute(String id, XxxFlowAction action, Boolean input) {
        validateRequest(id, action, input);
        XxxEntity entity = loadRequiredEntity(id);
        XxxFlowContext context = createContext(entity, input);
        return executeVersionedRule(entity, action, context);
    }
    // ...实现抽象方法
}

9.2 规范要点

  1. 入口方法必须 @Transactional(rollbackFor = Exception.class),保证状态落库与子表业务在同一事务。
  2. 以数据库快照为准:执行前重新 getById,禁止使用请求体中可被篡改的字段判断流程。
  3. 动作入参显式传递:审批结果、派工人员等通过命令对象或明确参数传入,禁止 Consumer<Context> 隐式修改上下文。
  4. 工厂编码必须来自数据库快照或登录会话,不能由请求体任意指定。
  5. 原状态作为并发更新条件,更新失败抛「状态已被其他请求修改」。
  6. 领域日志统一记录 businessId / instanceId / action / 原状态 -> 目标状态
  7. 新建后 chain 若允许省略,重写 isOptionalChain 返回 true,并重写 handleUnexecutedRule 给出明确语义(如保持原状态)。

10. 动作枚举规范

动作枚举同时定义基础 chain ID 与中文名称:

@Getter
public enum XxxFlowAction {
    CREATE("xxxCreate", "创建"),
    SUBMIT("xxxSubmit", "提交"),
    APPROVAL("xxxApproval", "审批");
    // ...
}
  • 一个动作对应一个基础 chain。
  • 审批通过 / 驳回是同一动作的不同结果分支,通过上下文人工结果区分,不拆成两个动作。
  • 动作名称用于日志和异常提示,保持中文可读。

10.1 现有动作映射

润滑计划 EmLubricationPlanFlowAction

动作 基础 chain 是否可选
CREATE lubricationPlanCreate 是(未配置保持编制中)
SUBMIT lubricationPlanSubmit
APPROVAL lubricationPlanApproval
COMPLETE_DISPATCH lubricationPlanCompleteDispatch

润滑工单 EmLubricationOrderFlowAction

动作 基础 chain
CREATE lubricationOrderCreate
CLAIM lubricationOrderClaim
SAVE lubricationOrderSave
SUBMIT lubricationOrderSubmit
ACCEPTANCE lubricationOrderAcceptance

11. 上下文(Context)编写规范

上下文是一次规则执行的业务数据载体,同时是并发控制与人工确认的契约。

11.1 规范要点

  1. 使用 @Data(Lombok),按领域独立建模。
  2. 需要人工确认(审批/验收/派工)的上下文实现 SDK 接口 BamsHumanConfirmationContext,提供 getHumanConfirmed()
  3. 固定携带:
  4. 业务主键(planId / orderId
  5. corpCode
  6. originalStatus(执行前数据库状态,作为并发条件)
  7. currentStatus(节点在内存中逐步推进的状态)
  8. humanConfirmed(人工结果,true/false 已处理,null 等待)
  9. 提供 transition(expectedStatus, targetStatus) 执行受约束的状态迁移,当前状态不符时抛 IllegalStateException,节点只能通过它推进状态,禁止直接 setCurrentStatus 绕过校验 (除非是 CREATE 起点等确需显式声明的场景)。
  10. 节点需要额外持久化业务字段时,通过变更意图标志表达(如 planEnableRequestedlubricationUsersUpdateRequested),由事务服务统一应用,节点不直接操作数据库。

11.2 示例(润滑计划上下文)

@Data
public class EmLubricationPlanFlowContext implements BamsHumanConfirmationContext {
    private String planId;
    private String corpCode;
    private Boolean humanConfirmed;
    private EmLubricationPlanStatus originalStatus;
    private EmLubricationPlanStatus currentStatus;
    private String lubricationUserIds;
    private String lubricationUserNames;
    private boolean lubricationUsersUpdateRequested;
    private boolean planEnableRequested;

    public void transition(EmLubricationPlanStatus expected, EmLubricationPlanStatus target) {
        if (currentStatus != expected) {
            throw new IllegalStateException("...当前为“" + currentStatus.getDisplayName()
                + "”,不能执行要求“" + expected.getDisplayName() + "”状态的规则");
        }
        currentStatus = target;
    }

    public void requestPlanEnable() { this.planEnableRequested = true; }
    public void requestLubricationUsersUpdate() { this.lubricationUsersUpdateRequested = true; }
    // prepareDispatch(...) 供派工入口设置输入并置 humanConfirmed=true
}

12. 节点(Node)编写规范

12.1 节点基类

每个业务提供一个节点基类,向 SDK 声明上下文类型:

public abstract class XxxFlowNodeSupport extends BamsTypedNodeComponent<XxxFlowContext> {
    protected XxxFlowNodeSupport() {
        super(XxxFlowContext.class);
    }
}

SDK 的 BamsTypedNodeComponent<C> 统一完成 getRequestData() 空值与类型校验, 业务节点通过 context() 获取类型安全的上下文。

12.2 节点类规范

  1. 使用 @LiteflowComponent(value = "...", name = "中文名") 声明稳定且唯一的组件 ID。
  2. 一个节点只描述一条状态边(一个 transition)。
  3. 重写 process() 只做「读取输入 → 校验前置状态 → 迁移状态 → 输出变更意图」, 禁止在节点内直接读写数据库
  4. 需要人工判断时,业务 XML 使用 SDK 公共节点 flowHumanConfirmation,不重复声明。

12.3 现有节点组件 ID 清单

润滑计划

组件 ID 迁移
lubPlanSubmitEffective DRAFT -> EXECUTINGrequestPlanEnable
lubPlanSubmitForApproval DRAFT -> PENDING_APPROVALREJECTED -> PENDING_APPROVAL
lubPlanApprove PENDING_APPROVAL -> PENDING_DISPATCH
lubPlanReject PENDING_APPROVAL -> REJECTED
lubPlanCompleteDispatch PENDING_DISPATCH -> EXECUTING,校验人员并 requestLubricationUsersUpdate + requestPlanEnable

润滑工单

组件 ID 迁移
lubOrderCreateAssigned PENDING_CLAIM -> PENDING_LUBRICATION
lubOrderCreatePendingClaim 声明PENDING_CLAIM(创建初始态)
lubOrderClaim PENDING_CLAIM -> PENDING_LUBRICATION
lubOrderStart PENDING_LUBRICATION -> LUBRICATING
lubOrderSubmit LUBRICATING -> PENDING_ACCEPTANCE
lubOrderAccept PENDING_ACCEPTANCE -> COMPLETED
lubOrderRejectAcceptance PENDING_ACCEPTANCE -> LUBRICATING

SDK 公共节点

组件 ID 类型 说明
flowHumanConfirmation 布尔节点 读取BamsHumanConfirmationContext.getHumanConfirmed(),用于 IF 分支

13. 规则 XML 编写规范

13.1 XML 位置与性质

tpm-backend-admin/src/main/resources/config/liteflow/*.el.xml

这些文件是规则源模板,不是线上运行时规则。运行时以 sys_liteflow.xml_content 中当前工厂的 ACTIVE 版本为准,通过 SDK 发布服务写入数据库并发布到 Redis Rule-DB。

13.2 定义链(必需)

每个版本必须声明一个定义链,只描述状态展示顺序,不参与业务流转:

<chain name="lubricationPlanDefinition">
    THEN(
        lubPlanReject.data('{"statusCode":"1"}'),
        lubPlanSubmitForApproval.data('{"statusCode":"2"}'),
        lubPlanApprove.data('{"statusCode":"3"}'),
        lubPlanCompleteDispatch.data('{"statusCode":"4"}')
    );
</chain>

要求:

  1. 字段名必须是 statusCode
  2. 值必须是状态枚举支持的编码。
  3. 顺序必须与实际业务流转一致。
  4. 服务自动在首位追加初始状态(如 DRAFT),并在末尾追加公共状态(如 DISABLED), 定义链只配置业务中间/终态。
  5. 定义链至少包含一个非初始状态节点。

13.3 动作链

<chain name="lubricationPlanCreate">
    THEN(lubPlanSubmitForApproval);
</chain>

<chain name="lubricationPlanApproval">
    IF(flowHumanConfirmation, lubPlanApprove, lubPlanReject);
</chain>
  • 动作链名使用基础 chain ID。
  • 人工确认用 IF(flowHumanConfirmation, 通过节点, 驳回节点)
  • flowHumanConfirmationtrue 走成功分支,false 走 ELSE 分支,null 会抛异常 (表示尚未获得人工结果)。
  • CREATE chain 可省略;其余动作 chain 缺失时执行器直接报错。

13.4 XML 示例:润滑工单(派工审批型)

<flow>
    <chain name="lubricationOrderDefinition">
        THEN(
            lubOrderCreateAssigned.data('{"statusCode":"1"}'),
            lubOrderStart.data('{"statusCode":"2"}'),
            lubOrderSubmit.data('{"statusCode":"3"}'),
            lubOrderAccept.data('{"statusCode":"4"}')
        );
    </chain>

    <chain name="lubricationOrderCreate">
        THEN(lubOrderCreateAssigned);
    </chain>

    <chain name="lubricationOrderSave">
        THEN(lubOrderStart);
    </chain>

    <chain name="lubricationOrderSubmit">
        THEN(lubOrderSubmit);
    </chain>

    <chain name="lubricationOrderAcceptance">
        IF(flowHumanConfirmation, lubOrderAccept, lubOrderRejectAcceptance);
    </chain>
</flow>

14. 规则发布与版本管理规范

14.1 运行时规则来源

运行时按以下条件从 sys_liteflow 读取当前激活版本:

app_code      = liteflow.rule-db.application-name
corp_code     = 当前工厂
template_code = 业务模板编码
status        = ACTIVE

14.2 SDK 发布服务

BamsLiteFlowRulePublisherService rulePublisher;   // 发布
BamsLiteFlowActiveTemplateService activeTemplate; // 激活/查询

核心方法:

方法 说明
publishXml(corpCode, templateCode, version, xmlContent) 解析 XML 并逐条 chain 发布到 Rule-DB
publishXml(appName, corpCode, templateCode, version, xmlContent) 指定应用作用域发布
hasActiveVersion(corpCode, templateCode) 是否存在 ACTIVE 版本
activateVersion(corpCode, templateCode, version) 激活指定版本
findActive / requiredActive 查询 ACTIVE 模板

14.3 发布与激活流程

  1. 选择目标工厂 corpCode 与模板 templateCode
  2. 确定新的不可变版本 version(如 v4),不要覆盖已有版本内容
  3. publishXml(...) 发布 XML;每条 chain 以 expectedVersion=0 发布,Redis 已存在同 ID 时 官方 Lua 原子拒绝,从而保证版本不可变。
  4. activateVersion(...) 激活:将目标版本置为 ACTIVE,同时把同一作用域旧 ACTIVE 降级为 PUBLISHED(事务内完成)。
  5. 等待至少一个轮询周期(当前 poll-seconds=3 秒)。
  6. 通过查询接口 / SQL 核对 ACTIVE 版本,再新建测试数据验证真实动作链。

14.4 版本切换约束

  • 只有尚未建立实例的新业务绑定新 ACTIVE 版本。
  • 已有 instanceId 的业务必须继续使用原版本,避免流程中途规则变化。
  • 禁止普通 SQL 直接覆盖历史版本 xml_content,会破坏版本不可变约束。

14.5 只读核对 SQL

SELECT app_code, corp_code, template_code, version, status
FROM sys_liteflow
WHERE app_code = 'tpm-admin'
  AND corp_code = '120101'
  AND template_code = 'lubrication-plan'
ORDER BY version DESC;

15. 事务、并发与 Redis 实例

15.1 事务与原子落库

  • 保存主表、子表与 CREATE 规则处于同一 Spring 事务调用链。
  • 持久化使用原状态作为更新条件:
UPDATE em_lubrication_plan
SET plan_status = :targetStatus, instance_id = :instanceId, ...
WHERE id = :planId AND plan_status = :originalStatus;
  • 更新行数为 0 时抛「状态已被其他请求修改,请刷新后重试」,实现乐观并发控制。
  • 先更新数据库、再写 Redis;Redis 写失败会触发数据库事务回滚。

15.2 Redis 业务实例

首次规则成功后,业务表保存 instance_id,同时 Redis 写入:

tpm:liteflow:instance:<templateCode>:<instanceId>

示例:

tpm:liteflow:instance:lubrication-plan:1b810ee1492a4db1b2fa1291f2134bec

值为 JSON:

{
  "instanceId": "1b810ee1492a4db1b2fa1291f2134bec",
  "applicationName": "tpm-admin",
  "id": "2086710739068497921",
  "corpCode": "120101",
  "templateCode": "lubrication-plan",
  "version": "v3"
}

后续动作会校验 idcorpCodetemplateCodeversion 归属。Redis 数据丢失或归属不一致时 服务拒绝流转,不会自动切换到工厂最新版本。

因此以下运维动作必须将实例 Key 空间作为业务数据处理:

  • Redis 清库或迁移;
  • Redis database 切换;
  • bams.flow.key 前缀变更;
  • 跨环境复制业务数据。

16. 现有业务示例对照

16.1 润滑计划(审批型)

创建 → DRAFT -> PENDING_APPROVAL
审批通过 → PENDING_APPROVAL -> PENDING_DISPATCH
审批驳回 → PENDING_APPROVAL -> REJECTED
派工完成 → PENDING_DISPATCH -> EXECUTING(isEnabled=1)

16.2 润滑计划(direct 型)

创建 → DRAFT -> EXECUTING(isEnabled=1)

16.3 润滑工单(派工审批型)

创建 → PENDING_LUBRICATION
首次保存 → PENDING_LUBRICATION -> LUBRICATING
提交 → LUBRICATING -> PENDING_ACCEPTANCE
验收通过 → PENDING_ACCEPTANCE -> COMPLETED
验收不通过 → PENDING_ACCEPTANCE -> LUBRICATING

16.4 润滑工单(领取直办型)

创建 → PENDING_CLAIM
领取 → PENDING_CLAIM -> PENDING_LUBRICATION
首次保存 → PENDING_LUBRICATION -> LUBRICATING
提交 → LUBRICATING -> PENDING_ACCEPTANCE
验收通过/不通过 → 同派工审批型

17. API 接口清单

统一网关前缀 /tpm-api

17.1 润滑计划 /em/EmLubricationPlan

方法 路径 说明
GET /flow/current-rule-nodes 查询当前工厂规则节点
POST /flow/submit 提交审批
POST /flow/approval 审批结果(工作流待接入)
POST /flow/complete-dispatch 派工完成
POST /saveOrUpdateWithDetails 新增/修改(新建触发 CREATE)
POST /getDetailById 详情查询
POST /batchEnable / /batchDisable 启停

17.2 润滑工单 /em/EmLubricationOrder

方法 路径 说明
POST /flow/claim 领取工单(当前登录人)
POST /flow/submit 提交验收
POST /flow/acceptanceInfo 提交验收信息
POST /saveOrUpdateWithDetails 新增/修改(新建触发 CREATE,待润滑触发 SAVE)
POST /getDetailById 详情查询

18. 开发约束与反模式

18.1 新增业务接入 LiteFlow 的步骤

  1. 定义状态枚举(code + displayName + fromCode)。
  2. 定义动作枚举(基础 chain + 中文名)。
  3. 定义流程常量类(TEMPLATE_CODEDEFINITION_CHAINSTATUS_CODE_FIELD)。
  4. 定义上下文(实现 BamsHumanConfirmationContext,含 originalStatus/currentStatus/transition)。
  5. 编写节点基类与各单一状态迁移节点。
  6. 编写 FlowService 继承 AbstractVersionedRuleFlowService,实现动作映射、结果校验、原子落库。
  7. 编写 XML(定义链 + 动作链),作为规则源模板。
  8. 通过 SDK 发布服务发布并激活版本。
  9. 控制器只做参数校验并转发 FlowService,不在控制器里拼流程逻辑。

18.2 反模式(禁止)

  1. 禁止在业务代码或 XML 中手工拼接版本化 chain ID。
  2. 禁止在节点内直接读写数据库。
  3. 禁止使用 Consumer<Context> 隐式修改上下文。
  4. 禁止重新引入 ruleVersion 字段形成重复状态源(实例已保存版本)。
  5. 禁止通过普通 SQL 覆盖历史版本 xml_content
  6. 禁止用请求体字段决定工厂或流程状态,工厂必须来自会话/数据库快照。
  7. 禁止把「保存/提交」等两个动作塞进一个接口的 saveFlag 隐式推进。
  8. 禁止为 direct 规则配置无业务意义的「跳过审批/派工」中间节点。

19. 故障排查

现象 主要原因 处理
规则执行后状态未落库 节点未迁移状态,或 chain 与当前状态不符 检查 XML chain 与节点前置状态
提示「状态已被其他请求修改」 并发已先变更状态 刷新详情后重试,不要重放旧状态
提示「规则未产生状态变化」 节点没有调用transition 检查节点逻辑
提示「LiteFlow 业务实例不存在」 Redis Key 丢失、前缀或 database 变更 核对instance_idbams.flow.key 与 Redis
提示「归属不一致」 计划/工单与实例的工厂、模板、主键不一致 核对数据迁移与复制
修改 XML 后行为未变 只改了 resources,未发布 ACTIVE 发布新版本并等待轮询
当前规则节点返回旧版本 ACTIVE 指针、appCode、corpCode 不匹配 核对sys_liteflow 与配置
提示缺少statusCode 定义链节点缺少data 或 JSON 非法 为每个定义节点配置合法{"statusCode":"..."}
更新后子项消失 全量同步被当成增量 查询详情后回传全部需保留子项

20. 附录:关键类速查

SDK 关键类

作用
BamsVersionedLiteFlowExecutor 版本化规则执行入口
BamsVersionedFlowRequest / BamsVersionedFlowResult 请求/结果不可变模型
BamsLiteFlowTemplateService currentVersion / versionedChain
BamsLiteFlowChainService chain 查找 + Rule-DB 候选加载
BamsLiteFlowInstanceRepository 固定版本实例 SPI(默认 Redis)
BamsLiteFlowRulePublisherService 数据库 XML 发布 / 激活
BamsLiteFlowActiveTemplateService ACTIVE 查询 / 版本激活
BamsTypedNodeComponent<C> 类型安全节点基类
BamsHumanConfirmationContext / BamsHumanConfirmationNode 人工确认契约与公共节点

业务关键类

作用
AbstractVersionedRuleFlowService<E, C, A> 版本化规则调用模板方法
XxxFlowAction 动作 → 基础 chain 映射
XxxFlowCommand 不可变执行命令
XxxFlowContext 单次规则执行上下文
XxxFlowNodeSupport 业务节点基类
XxxFlowService 业务规则编排服务

常量与命名

约定
模板编码 小写短横线,如lubrication-plan
定义链 业务名 +Definition,如 lubricationPlanDefinition
状态字段 statusCode
版本 v[0-9]+
chain 分隔符 __(双下划线)
实例 Key {bams.flow.key}{templateCode}:{instanceId}