开源工作流别再硬堆 if‑else!我把 Slickflow 改造成可插拔中国式 OA 引擎 SailFlow
提示:项目还在持续迭代,存在破坏性变更,暂时不要直接上生产环境,架构基线已经成型,欢迎.NET 同行一起交流。
搞过 OA 审批流开发的朋友,大概率都踩过这种坑:
产品今天过来:这个节点要支持抢办;
过一周又改:要按组织单位映射选人;
再过几天:驳回之后单据要回送给打回人......
需求来一次,引擎内部就堆一堆if‑else。折腾几个版本之后,代码越堆越厚,后面谁都不敢碰,改需求如同拆炸弹。
作为.net老猿,折腾过许多工作流,总感觉不太趁手。一直想独立写,苦于没有精力。AI暴风时代,给我这种思想大于精力的给与了可能!那就开始吧,扬帆启航! sail-flow
基于开源项目 Slickflow,我做了二次深度改造,新项目命名 SailFlow,目标非常明确:插件式可插拔、多数据库适配,面向 .NET 6 / 8 /10,专门解决中国式 OA 审批的各类复杂场景。
开源仓库地址:
https://github.com/sailuosi/SailFlow
项目基于 MIT 协议,致敬上游 Slickflow,授权声明保留;数据层、数据结构、前端部分均已改造,后续独立演进,不再同步上游源码。gitee也有同名仓库。
SailFlow 到底是什么?
简单一句话:这是一套可以嵌入你自己业务系统的流程引擎内核,不绑定任何前端页面、菜单、办理工作台。
鉴权、业务菜单、办理页面全部留给宿主业务系统去实现,引擎内核只专心管好流程本身:
- 流程启动、流转、驳回、加签撤回等流转逻辑
- 审批人解析,节点放行判断
- 业务校验、业务副作用、待办通知的挂载扩展
不用被迫使用整套成品 OA,拿来嵌入自己现有系统即可。
核心设计思想:一项能力,一个 UseXxx
借鉴ASP.NET Core 的能力启用思路,所有扩展能力全部显式插拔,不用就不引入对应依赖。
csharp
var client = SailClient.CreateBuilder(configuration)
.UseDatabase(...) //配置数据库
.UseBizAssignees() //配置个性化待办人逻辑
.UseBizRules() //配置业务规则
.UseBizMsg() //配置消息体系
.UseBizLocalize() //配置语言
.UseSailData() //配置数据体系
.UseFlowHook(...) // 配置回调与钩子
.Build();
只引用 NuGet 程序集,但不调用UseXxx方法,对应的扩展插槽就是空实现。
真正做到按需加载,不会仅仅引用引擎,就被动把 RabbitMQ、脚本引擎、规则引擎全部一股脑带入项目,拒绝隐形重型依赖。
三层架构分层:pure /ext/biz,重依赖不许污染内核
严格控制依赖方向,只允许上层依赖下层:
Host 宿主业务应用
└─ biz(业务门面、默认能力组合)
└─ core/ext(可选组件:MQ、脚本、规则引擎、表单实现等,可替换)
└─ core/pure(引擎骨架、流程契约,禁止重型NuGet包)
└─ mooSQL
- pure 层:纯粹流程语义、管道骨架,不引入重第三方组件
- ext 层:MQ、Python 脚本、规则引擎等可选扩展,可替换可裁剪
- biz 层:薄门面封装,只是转发调用,不写复杂内核逻辑
把过去 "MQ、邮件硬耦合引擎内核" 的历史债务全部清理干净。
契约下沉,实现上浮,内核保持干净,业务实现放到扩展层。
适配中国式 OA:不要硬套国外 Flowable 的概念
国内审批,最看重两件事:办理动词、办理模式,SailFlow 把二者做了分离,拒绝把复杂业务揉进一个枚举里面。
✅ 办理动词(内置码表)
通过、驳回、退回、加签、抄送、撤回、重发、跳转、关闭、转办......
其中重发 Resend 属于 SailFlow 特色能力,专门适配 "单据退回修改完成后,回送给原打回人复核" 这类国内高频场景,不是简单点一次同意。
✅ 办理模式(Leave,代表节点放行规则,不是页面按钮)
抢办、协办、组间抢办 / 协办、队长关卡等模式。
先定义清楚:节点要多少人办理完成,流程才可以往下走,再去定义页面按钮文案,而不是靠一个万能按钮吞掉全部业务语义。
退回逻辑同样做二维拆解:
- 退到哪里:上一跳、发起人、任意历史节点;
- 修改完成后如何发送:直接向下流转,还是返送给驳回人复核。
比起硬搬国外 BPMN 枚举,这套模型更贴合国内 OA 真实业务。
最头疼的待办人:双时刻管道,专治各种奇葩选人规则
OA 开发 80% 的坑,都出在 "该找谁审批" 这件事上。
SailFlow 把选人逻辑拆成两个时间点:
- Resolve(生成待办之前):解析出本节点需要哪些人来处理;
- Leave(节点推进之前):判断当前处理情况,节点是否允许放行离开。
配置统一采用{Type,Params}结构,按字符串 Type 注册,支持业务层覆盖重写,严禁通过修改内核、大量 if‑else 分支去实现业务选人逻辑。
内置已经支持大量解析策略:
固定人员、角色组、流程相对人、发起人自选、发送人自选、单位映射、岗位相对、业务回调、表达式、兜底策略等等。
内置放行模式:竞争抢办 Race、会签协作 Collaborate、分组 Group、队长 Captain 模式等。
几条工程上硬性约定:
- 组织分组 Group 和企业单位 Unit 正交区分,禁止拿 GroupId 冒充组织单位;
- 组织主数据全部保存在宿主系统,引擎只保留查询钩子;
- 选人配置缺失、解析为空办理人时:直接拒绝推进流程,返回明确错误码,不会静默把办理人改成发起人或者管理员,避免流程悄无声息异常;
- 待办办理人、消息通知、抄送三者完全三线分离,互不混淆。
一套管道扛住各类企业复杂组织选人需求。
事件体系:Gate / Hook / Notifier + Outbox,职责彻底分开
很多工作流引擎把校验、业务回调、消息通知全部混在一起,调试排查灾难。SailFlow 做了职责拆分:
- Gate:流转前置校验,业务层可以直接拒绝本次流转;
- Hook:流转完成之后执行业务副作用逻辑;
- Notifier:专门处理待办消息通知旁路逻辑。
同时支持同步执行、Outbox 异步消息、失败重试、死信、指标埋点插槽。
每一类能力,对应一个UseXxx扩展,能力开关、数据表初始化、消息消费 Drain 全部内聚,不会在 Build 完成之后到处散落注册代码。
运维视角:分表、冷热归档不是后期补丁
很多流程引擎跑个几十万条实例之后,数据库性能直接崩盘。SailFlow 面向十万级年发起量做了设计,冷热分离可配置(默认关闭):
- 业务热路径只访问热数据表;
- 历史冷数据按年分表:*_hist_YYYY;
- 流程轨迹、流程变量,支持按流程定义白名单开启分表;
- 引擎日志输出 Sink、日志粒度完全可配置。
流程能跑起来只是及格;长期运行数据库不崩,才算真正落地。
SailFlow 适合谁?不适合谁?
✅ 适合场景
- .NET 技术栈团队,需要把流程引擎嵌入自有后台系统;
- 大量中国式审批,加签、抢办、退回返送等需求多;
- 审批人计算规则五花八门,不想每次改业务都动内核;
- 需要按需挂载 MQ、脚本、规则、AI 节点,追求轻量化可控。
❌ 暂时不适合
- 想要开箱即用完整 SaaS 审批产品,零代码直接上线;
- 无法接受迭代期破坏性变更,直接用于生产环境。
技术栈总览:.NET 多目标框架 + mooSQL 多数据库 + BPMN(sf 扩展标签)+ 插件管道模型
写在最后
现在开源工作流项目,不缺长长的功能清单。
真正稀缺的,是干净的扩展点。业务上来各种奇葩需求,你敢不敢不改引擎内核分支,只在外部扩展就搞定。
SailFlow 的设计赌注就在这里:
- UseXxx 显式启用,拒绝隐形依赖;
- pure 内核不背重型第三方包;
- 待办人双时刻管道处理复杂选人;
- 中国式办理动词与模式专门适配国内 OA;
- Gate/Hook/Notifier/Outbox 事件职责分离。
MIT 开源,欢迎正在跟审批流死磕的小伙伴,前往仓库看能力基线,提 Issue、PR 一起打磨。
仓库地址:
https://github.com/sailuosi/SailFlow
仓库配套文档清单
表格
|---------------------|--------------------------------|
| 文档 | 用途 |
| README.md | 项目总览与能力一览 |
| 特性说明‑引擎能力基线.md | 命令、节点、插槽基准说明 |
| 特性说明‑待办人管道.md | 审批人解析专项文档 |
| 特性说明‑中国式 OA 审批要素.md | 办理动词与模式完整对照 |
| 架构设计‑项目依赖与分层.md | pure/ext/biz 分层详解 |
| 特性设计‑回调与事件.md | Gate/Hook/Notifier/Outbox 事件体系 |