Slickflow 规则集与 NRules 集成实践:从设计到产品落地

Slickflow 规则集与 NRules 集成实践:从设计到产品落地

1. 背景与目标

工作流引擎中的 Business Rule Task(规则任务) 需要把「业务规则」从流程图里抽离出来:规则可复用、可版本化、可独立测试,而 BPMN 只负责 选哪套规则把流程变量交给规则

本实践在 Slickflow 中落地 规则集(Rule Set) ,并集成开源规则引擎 NRules ,同时支持 程序集规则(强类型 C# Rule)JSON DSL 规则(声明式 when/outputs) 两种形态,统一落在数据库表 wf_rule_set ,由 RuleSetExecutionManager 按模式调度执行。


2. 总体架构:数据、引擎、建模三层解耦

层级 职责
仓储 wf_rule_set 规则集编码、名称、moderule_content、启用状态等
执行 RuleSetExecutionManager mode 解析 rule_content:NRules 或 JSON DSL
流程建模 BPMN 扩展 RuleTask 上只绑定 ruleSetCode;运行时从库加载完整定义

这样 规则本体流程定义 XML 解耦:同一套规则可被多个流程/节点引用;更新规则主要改表数据或发布流程版本,而不必反复改 BPMN 里的规则正文。

2.1 请假流程:规则任务与排他网关(文字版流程图)

下面用 请假业务 把「规则集算出的结果如何驱动 BPMN」说清楚:流程里只有 一套规则集 (例如绑定 LeaveApproveRule 或等价的 DSL),规则内部按 三种互斥情形 写出 ApprovalLevel排他网关 再按该变量走 三条出线 ,分别对应三种审批路径------这与 LeaveApproveRuleLeader / Manager / HR 三档一致。

参与者与变量约定: 员工提交请假时,流程中已有(或经表单写入)LeaveDays(天数)、LeaveType(类型,如事假、病假等)。规则任务执行前,这些量作为规则输入;执行后,规则向流程变量写入 ApprovalLevel ,供网关条件引用。

节点顺序(自上而下、与典型 BPMN 泳道图一致):

  1. 开始事件 --- 流程实例创建,进入请假子流程。
  2. 用户任务:填写 / 提交请假申请 --- 申请人确认天数与类型,数据落入流程变量(及必要时 wf_variable 声明的 Input,供规则任务引用)。
  3. 业务规则任务(Business Rule Task) --- 绑定 wf_rule_set 中的请假规则集(ruleSetCode)。引擎调用 RuleExecutorRuleSetExecutionManager,根据 mode 执行 NRules 或 JSON DSL,唯一输出路由键ApprovalLevel
  4. 排他网关(Exclusive Gateway) --- 以 ApprovalLevel 为唯一判别依据,三条出线互斥 ,同一实例只激活其中一条:
    • 分支一: ApprovalLevel == "Leader"用户任务「直属领导审批」(短假、常规情形,由组长 / 主管处理)。
    • 分支二: ApprovalLevel == "Manager"用户任务「部门经理审批」(例如天数超过 3 天且未落入 HR 档)。
    • 分支三: ApprovalLevel == "HR"用户任务「人事审批」(例如超过 7 天或病假等需人事备案的情形)。
  5. 汇合 --- 三条审批任务完成后,经 排他网关或并行汇合结构(依建模习惯二选一)汇聚到同一后续路径(如「通知申请人结果」或「归档」)。
  6. 结束事件 --- 流程完结。

要点: 网关上的三条条件不是再写三套独立「业务规则」,而是 消费规则任务已写好的同一个变量 ;「三种规则」体现在 规则集内部LeaveDaysLeaveType 的分支判断(NRules 里 ApplyApproval 的三段 if / else if / else,或 DSL 里多条 when),流程图侧则 一规则任务 + 一网关三分支,职责清晰、易测易改。


3. 规则集两种执行模式

3.1 ruleTypes:NRules 程序集规则

rule_content 为 JSON,包含 ruleTypes 数组,元素为 程序集限定名 (与 NRules Rule 派生类一致)。

运行时:

  1. RuleRepository 加载类型并编译会话;
  2. 注入 RuleInputFact (变量字典)与 RuleOutputFact(输出字典);
  3. session.Fire() 执行规则,从输出字典取结果(如 ApprovalLevel)。

适合:复杂分支、需强类型与单测、与现有 .NET 业务规则类复用。

下面是与「请假审批级别」对应的 NRules 规则类 完整示例(引擎通过 ruleTypes 中的程序集限定名加载该类;RuleInputFact / RuleOutputFact 由引擎注入,变量从 input.Vars 读取,结果写入 output):

源码位置: sfbpmn-project/core/Slickflow.Module.BusinessRule/Approval/LeaveApproveRule.cs

csharp 复制代码
using NRules.Fluent.Dsl;
using Slickflow.Engine.Business.Entity;
using System.Globalization;

namespace Slickflow.Module.BusinessRule.Approval
{
    public class LeaveApproveRule : Rule
    {
        public override void Define()
        {
            RuleInputFact input = null!;
            RuleOutputFact output = null!;

            When()
                .Match(() => input)
                .Match(() => output);

            Then()
                .Do(_ => ApplyApproval(input, output));
        }

        private static void ApplyApproval(RuleInputFact input, RuleOutputFact output)
        {
            var days = 0;
            var leaveType = string.Empty;

            if (input.Vars.TryGetValue("LeaveDays", out var d) && d != null)
            {
                var rawDays = Convert.ToString(d, CultureInfo.InvariantCulture);
                if (!string.IsNullOrWhiteSpace(rawDays)
                    && int.TryParse(rawDays, NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsedDays))
                {
                    days = parsedDays;
                }
            }

            if (input.Vars.TryGetValue("LeaveType", out var t) && t != null)
                leaveType = t.ToString() ?? string.Empty;

            if (days > 7 || leaveType.Equals("Sick", StringComparison.OrdinalIgnoreCase))
                output.Set("ApprovalLevel", "HR");
            else if (days > 3)
                output.Set("ApprovalLevel", "Manager");
            else
                output.Set("ApprovalLevel", "Leader");
        }

    }
}

3.2 bindingsJson(表字段名,含义为 JSON 规则 DSL)

此处 mode = bindingsJson 表示 rule_content 内是 JSON DSL ,与早期 BPMN 上曾出现的同名「变量绑定」概念已区分;任务节点不再承载大块绑定 JSON,避免与 wf_rule_set.rule_content 混淆。

rule_content 形如:

  • 顶层 stopOnFirstMatchrules 数组;
  • 每条含 namewhen(条件表达式)与 outputs(输出键值);
  • 按数组顺序匹配stopOnFirstMatch: true首条命中即停止

适合:规则变更频繁、希望少发版、由运营/实施直接改 JSON 的场景。

DSL 模式示例 (入库到 wf_rule_set.rule_contentmodebindingsJson;变量名 LeaveDaysLeaveTypeApprovalLevel 与流程/规则输入约定一致即可):

json 复制代码
{
  "stopOnFirstMatch": true,
  "rules": [
    {
      "name": "ShortSickLeave",
      "when": "LeaveDays <= 3 || LeaveType == \"Sick\"",
      "outputs": {
        "ApprovalLevel": "Leader"
      }
    },
    {
      "name": "LongLeave",
      "when": "LeaveDays > 3",
      "outputs": {
        "ApprovalLevel": "Manager"
      }
    }
  ]
}

说明:上例与上一节 LeaveApproveRule.cs 的分档逻辑 不必完全一致------前者用声明式条件快速迭代,后者用 C# 实现更细的分支(例如病假、超过 7 天走 HR);产品可按同一业务域分别维护两套实现或逐步对齐语义。


4. 与 Slickflow 产品的集成路径

4.1 引擎侧:RuleExecutorRuleSetExecutionManager

  • RuleExecutorSlickflow.Engine)在 RuleTask 执行时:

    • ruleSetCodewf_rule_set 取实体;
    • 组装 规则输入字典 ,调用 RuleSetExecutionManager.Execute
    • 将输出写回 wf_process_variable(活动作用域),供后续网关、任务使用。
  • RuleConfigDetail 除 BPMN 中的 ruleSetCode 外,可在解析流程时 MergeFrom 合并表字段(名称、描述、rule_contentmode 等),便于调试与 API 展示;执行仍以库表为准,避免 BPMN 与库不一致。

4.2 变量输入:流程变量 + wf_variable 定义

规则入参需要与流程数据对齐:

  • 流程级 / 活动级 wf_process_variable 提供运行时值;
  • wf_variable 描述当前活动上的变量定义:方向、是否引用前序节点、source_ref / source_variable_name 等。

RuleTask 组装输入时:先尊重 wf_variable 中声明的 Input ------引用型输入从前序活动实例的 wf_process_variable 按引用解析;未声明则回退为合并活动变量(兼容旧流程)。声明了输入但暂无值时写入空字符串 ,避免 JSON DSL 中 LeaveType == "Sick" 等表达式因缺键导致整条规则无法命中。

4.3 模式枚举与 API

  • 使用 RuleSetModeEnumruleTypes / bindingsJson)与 RuleSetModeHelper 做持久化字符串与枚举互转,避免散落魔法字符串。
  • sfdapi RuleSetController 在保存时校验 moderule_content 形状,保证入库数据可被引擎执行。

4.4 设计器(sfd)

  • Modeling 菜单进入 业务规则设置 ,维护规则集列表与 rule_content

  • RuleTask 属性里选择 规则集编码 ,与引擎读取路径一致。


5. 开发过程回顾:关键决策

  1. 规则与流程分离 :规则集中在 wf_rule_set,BPMN 只存 ruleSetCode,降低模型体积与合并冲突。
  2. 双模共存 :NRules 适合工程化规则类;JSON DSL 适合轻量、快速调整;用 mode 明确分支,避免隐式猜测。
  3. 任务侧不再承载「规则绑定 JSON」:变量来源改为流程库表与命名约定,减少重复配置与歧义。
  4. 空值与 DSL:输入字典对声明变量给默认空串,减少「条件看似正确却永不命中」类问题。
  5. 运维注意:若流程定义启用内存缓存,更新 XML/规则后需关注缓存与实例版本,避免「库已改、内存仍旧」的错觉。

6. 小结

Slickflow 规则集功能将 NRules自研 JSON DSL 执行器 统一在 RuleSetExecutionManager 之下,通过 wf_rule_set.mode + rule_content 驱动;RuleTask 只负责绑定规则集与喂入流程变量,从而形成清晰的分层:产品(建模/API)→ 引擎(执行与持久化)→ 规则运行时(NRules 或 DSL)

后续可在同一套扩展点上增加规则版本、审计日志、规则仿真接口等,而不必改动 BPMN 核心结构。


本文基于 Slickflow 仓库中 RuleSetExecutionManagerRuleExecutorVariableManagerwf_rule_set 等相关实现整理,如有变更以当前代码与数据库脚本为准。

相关推荐
slickflowteam7 天前
Slickflow 与 OpenClaw 结合实践:技术原理、集成方式与 Skill 说明
bpmn·ai工作流·.net工作流
问道飞鱼11 天前
【前端知识】React Flow : 一个基于 React 的可视化节点编辑器框架
前端·ai工作流·react flow
arbboter14 天前
【AI编程】约束即设计:AI时代的人机边界重构
ai编程·ai工作流·人机协作·trae·声明式执行·流程编排
无心水24 天前
【OpenClaw:实战部署】10、OpenClaw自动化调度——打造7x24小时无人值守AI工作流
人工智能·ai·ai工作流·openclaw·openclaw·三月创作之星·养龙虾
slickflowteam1 个月前
Slickflow.NET 基于 AI 大模型实现智能客服多轮问答系统
bpmn·ai工作流·.net工作流
slickflowteam1 个月前
.NET 开源工作流:Slickflow 流程自动化运行技术指南
bpmn·.net工作流
OEC小胖胖2 个月前
DeepSeek导出文档
人工智能·效率工具·知识管理·ai工作流·deepseek
分享牛2 个月前
大模型结合BPMN语言,下一代BPM产品的雏形
人工智能·搜索引擎·llm·bpmn
分享牛2 个月前
Camunda 7停止维护后,bpm开源流程引擎新局面
流程图·流程引擎·bpmn·cmmn