Flowable这个开源工作流引擎在我们系统里躺了大半年之后我终于决定在它上面再盖一层统一流程平台。说实话这一步不是一开始就想好的而是被现实逼出来的最初只是想找一个能画BPMN流程图、能跑审批的引擎结果半年后十几个业务系统都在各自调Flowable的API每个项目组自己部署一套流程模型散落各处待办任务互相看不见。写这篇文章是想把我们从“裸用Flowable”到“建设统一流程平台”的完整过程、关键设计和踩过的坑整理出来给正在用工作流引擎、或者正准备做流程中台的团队一个参考。这篇文章适合三类人一是已经用上Flowable、但觉得有点失控的开发者二是正在做流程平台选型或架构设计的技术负责人三是对BPM、工作流领域感兴趣、想了解这套东西落地长什么样的同学。我会从为什么选Flowable开始讲然后说清楚Flowable直接使用会遇到的典型问题再重点展开统一流程平台的整体设计、核心实操细节、以及我在真实业务里踩过的坑和排查思路。内容会以实际可落地的方案为主不是泛泛的架构概念。1. 为什么拿Flowable当起点先说一个很多人会问的问题既然最终要做统一流程平台为什么不一开始就自己写一套流程引擎说实话工作流引擎这件事看起来不难无非就是“节点流转、条件判断、任务分配”但真要把BPMN 2.0的网关、子流程、事件、多实例、定时器都做稳定没有一两年持续投入是做不出来的。所以当时我们很务实地选择了先站在Flowable的肩膀上。1.1 Flowable到底是什么Flowable是基于BPMN 2.0标准的开源工作流引擎它起源于更早的Activiti 5/6分支后来独立发展目前社区版和企业版并行。核心能力包括解析和执行BPMN 2.0流程定义、维护流程实例和任务、记录历史数据、支持定时器、消息事件、信号事件以及比较完整的表单集成方案。Java生态里用得非常广这也是我们当时选它的一个重要原因——团队都是Java背景排查问题、二次开发都比较顺手。在Flowable里几个核心对象要心里有数流程定义ProcessDefinition相当于“图纸”部署好之后不可变流程实例ProcessInstance是按图纸创建的一次具体流转相当于“一栋按图建出来的楼”任务Task是流转过程中待办的一个节点执行实例Execution则更细代表当前运行到哪条分支。理解这几个概念的层级关系后面做平台封装才会心里有底。1.2 选Flowable而不是自己造轮子的三个理由第一BPMN 2.0的覆盖面很全。会签、或签、并行网关、排他网关、子流程、边界事件、补偿事件这些都是业务上非常高频的需求自己从零写一个能让模型稳定跑在生产环境的引擎工作量远超想象。第二Flowable的表结构公开、数据模型清晰运行实例、任务、历史都分开存放对于做监控和二次开发非常友好。第三它的API设计相对稳定RuntimeService、TaskService、HistoryService、RepositoryService这些核心服务接口多年没有大变动意味着平台层可以相对稳定地建立在它之上。当时我们是拿一个请假审批的Demo做了验证部署流程图、发起流程、查待办、审批通过、查询历史半天时间全部跑通。这个速度让我们很确定流程引擎本身不需要自己写精力应该放在业务能力的抽象上。但也是从这个时候开始隐患已经埋下了。2. Flowable直接裸用用着用着就疼了流程引擎跑起来之后业务团队很快发现这东西好用于是“请假审批”刚上线紧接着就有报销、合同、采购、出入库等各种流程需求找过来。每个系统各接各的Flowable看着热闹实际是问题的集中爆发期。2.1 最直接的问题业务代码和流程代码纠缠不清在裸用阶段每个业务系统都要自己维护一套启动流程、处理任务的代码。比如一个业务系统要发起审批它要做的事包括往自己的业务表里插一条单据数据再调flowable的RuntimeService.startProcessInstanceByKey发起流程还要准备一个业务表主键和流程实例ID的映射关系审批回调时再根据流程实例ID去反查业务数据。这套代码写一次两次没问题写了十几个系统之后问题就来了每个系统的映射方式不一样有的用businessKey有的用流程变量有的自己在扩展表里存关联后续做统一查询、统一待办的时候数据根本对不齐。更麻烦的是没经过平台约束的流程模型写起来很随意。有的流程把所有审批逻辑塞进一个ServiceTask里有的把业务规则写在网关条件表达式里有的干脆用排他网关模拟一切。流程图最后沦为了摆设真真正正的逻辑都藏在Java delegate里流程定义换代时根本不敢动。2.2 重复建设与权限割裂审批意见、加签、转办、撤回、催办、待办提醒这些跟流程强相关但又非常通用的功能我们当时在每个系统里都重复实现了一遍。A系统写了一套加签逻辑B系统又写了一套实现方式还不一样——有的用Flowable的ADD_AND_APPROVE变更任务办理人有的直接在任务变量里存了一个加签人列表由应用层自己判断处理。这套东西的时间成本和维护成本都很高。还有一个让人头疼的问题是权限割裂。岗位A的管理者在系统1里能看到待办在系统2里又得重新配置一遍权限才能看到那套流程的待办同一个人的待办任务散落在多个系统里没有一个汇总视图。用户每天都得去各个系统里翻一遍有没有需要自己审批的单子。这种体验很差而这其实是流程平台治理缺失的典型表现——流程引擎只是提供了“流转”的技术能力并没有把“人的视角”统一起来。2.3 运维与治理基本是空白Flowable裸用阶段运维基本是靠“流程没跑挂就没人管”。某次有一个定时器任务因为执行节点所在服务重启一批定时器全部错过触发时间要不是业务人员反馈“单子卡住了”我们根本发现不了。再比如流程模型更新当时直接覆盖部署结果因为新版本的流程图里删了一个节点导致还在途的旧流程实例在查询任务时出现空指针最后只能手工改数据库才把流程救回来。还有一个隐藏问题历史数据无限膨胀。Flowable默认会往历史表里写大量数据ACT_HI_ACTINST这张表几乎记录了流程实例的每一个执行节点动作高并发流程跑上几个月这张表就是千万级起步。我们没有做归档策略数据库越来越慢最后拖累了正常的流程任务查询。到这一步我们基本意识到Flowable解决的是“单个流程怎么跑”的问题而公司需要的其实是“所有流程怎么被管起来、被统一使用”的问题。这二者之间有巨大的工程缺口。3. 统一流程平台设计的关键决策统一流程平台这个东西说起来容易做起来需要非常清醒地想清楚一个问题我们做的到底是一个给开发者调用的SDK还是一个给全公司业务系统使用的平台。这两者的设计思路完全不同。我们最后明确平台必须成为一个独立的、可独立部署的中间层Flowable只是这个平台内部的一个引擎组件对外完全屏蔽。3.1 平台定位流程资产的统一管理入口统一流程平台的本质是把自己定位成所有流程资产的统一管理入口。所有流程模型都必须在平台上注册所有流程的发起、审批、查询、归档都通过平台进行业务系统不允许绕过平台直接操作引擎底层API。听起来像是一刀切的规定但实际上这是避免失控最有效的手段。平台化之后各个业务系统的角色从“自己管流程”变成了“向平台申请流程能力”。比如业务系统需要一个新的审批流程开发同学只需要在平台上设计BPMN模型、配置好表单地址和权限策略、申请一个唯一的流程Key然后通过统一的API发起流程、接收回调即可。流程模型、运行数据、历史数据、待办权限全部沉淀在平台侧方便统一治理。3.2 两个决定性架构决策第一个决策统一入口。所有流程发起统一走平台的“发起流程”开放接口而不是允许业务系统直接new一个ProcessEngine然后调用startProcessInstanceByKey。这样做的好处非常实际平台可以在发起的必经之路上做权限校验、参数规整、幂等控制、数据埋点。第二个决策统一运行时。Platform模式即平台内部只维护一个Flowable引擎实例所有流程跑在同一个引擎上。而不是每个业务域独立部署引擎实例来跑自己的流程。统一运行时的好处是待办任务天然就汇合在一起查询所有系统流程的待办只需要对ACT_RU_TASK表做一次查询不需要跨库联表。这两个决策做下来后面很多模块就顺理成章了。3.3 整体架构分层我们的平台架构大致是四层最上层是接入层也叫Open API层面向业务系统提供发起流程、审批、查询、撤回等统一接口。接入层负责身份鉴权、参数校验、数据权限过滤业务系统通过这些接口与平台交互不感知底层引擎。往下一层是流程编排层负责流程模型的注册、流程分类管理、表单配置、权限策略配置、流程扩展点配置。这一层做的是“建模与业务策略的绑定”比如某个流程发起前要校验什么、审批通过后要回调哪个系统都在这一层配置。第三层是引擎适配层这是对Flowable的二次封装。把RuntimeService、TaskService、HistoryService等原生API包装成平台内部的服务并补充了流程实例与业务单据的关联映射、统一任务模型、事件监听分发等能力。最底层是数据层包括Flowable自身的ACT_*表以及我们自己补充的业务关联表、平台配置表、扩展字段表。数据层做的事情很简单让平台的数据模型能自洽地支撑上层业务。3.4 平台的核心模块统一流程平台从功能上可以拆成几个核心模块。流程模型管理模块负责BPMN文件的上传、校验、部署、版本管理、下线处理。这个模块把“流程模型”从开发者的本地文件变成平台的可管理资产。流程运行模块负责发起流程、驱动任务流转、处理各类事件。这个模块封装了Flowable最核心的运行时操作是业务系统调用最频繁的地方。任务中心模块负责统一展示所有待办、已办、抄送、我发起的任务。它不只从Flowable取任务数据还要聚合业务摘要、表单地址、优先级、超时信息等让用户在一个页面处理所有系统的审批。权限与策略模块负责流程发起权限、任务操作权限、数据权限的集中控制。这块是平台能否落地的关键后面实操章节我会细说。监控运维模块负责流程积压、超时、异常实例、历史数据归档等运维能力。没有这个模块平台就只是个能跑的引擎而不是一个能长期稳定服务的平台。4. 核心实操从裸用Flowable到平台化改造平台化的改造不是重新写一套系统而是一个个把能力收拢到平台侧的过程。下面按实操顺序讲每一步都是我们能直接复用的经验。4.1 流程定义统一注册与管理第一步把所有存量流程模型收拢到平台统一管理。我们建了一张流程模型注册表我们叫PROC_MODEL_REG字段包括流程Key、流程名称、所属分类、版本号、部署ID、状态草稿/已发布/已下线、负责人、表单标识、回调地址。这张表是流程资产的“户口本”所有模型在平台里都有一个正式档案。一个容易出错的地方是Flowable自身的流程定义版本机制。同一个流程Key每次部署会生成一个新的流程定义ID带有版本号。如果业务系统用老的部署方式直接按Key发起流程Flowable默认会使用最新版本。这在流程在途的情况下容易出问题明明A流程实例是上个月发起的中间的逻辑应该按旧版本来但新发起的流程已经使用了新版本。我们的做法是在注册表里维护每个流程当前允许发起的最小版本和默认版本发起流程前明确指定要使用的部署版本避免模糊匹配。BPMN文件的来源也要管好。我们从一开始就确定了“模型入库 Git备份”双保险BPMN文件上传到平台后既存一份到数据库用来部署和展示也同步提交一份到Git仓库用来追溯和Diff。上线一段时间后回头看这个习惯救了我们好几次——某次模型误覆盖我们就是靠Git历史版本还原的。4.2 发起流程的统一入口发起流程是业务系统使用频率最高、也最容易出问题的一个动作。平台提供的“发起流程”接口我们定义为platform.startProcess(procKey, businessId, operatorId, variables)。其中businessId是业务系统里的单据主键operatorId是发起人variables是这次流程携带的业务变量。这里重点说businessId的用法。我们要求业务系统必须以业务单据主键作为业务关联标识平台内部会维护一张流程实例与业务单号的关联表PROC_BIZ_REL。这个设计解决了之前在途流程单和流程实例映射混乱的问题。后续所有“根据单据查流程状态”“根据流程实例查业务单号”的操作都只查这一张表性能非常好逻辑也干净。发起流程前平台要做三件事一是校验这个业务系统是否有权发起该流程Key二是校验该流程Key当前是否在可发起状态而不是已下线三是做幂等控制。幂等控制这点特别容易被忽略但实际很重要。比如前端按钮被双击或者消息队列重复投递如果同一个businessId重复发起流程就会产生多条重复的流程实例业务上很难处理。我们的方案是在PROC_BIZ_REL里给businessId和procKey建唯一索引重复发起时直接拦截并返回原流程实例ID而不是新建。4.3 统一任务中心与任务操作统一任务中心是平台让用户“有感”的关键模块。它要做的事情是把Flowable的待办任务加上业务摘要、表单地址、优先级、截止时间等维度后统一展示给用户。TaskService.createTaskQuery()直接用起来很快会发现几个问题。第一待办任务查询条件复杂后SQL不好优化第二Flowable返回的任务对象上没法直接关联业务摘要比如“采购申请单号PO20250801”这种信息需要二次回业务表查询第三权限过滤如果靠Flowable的taskCandidateUser表达式配置起来非常繁琐且不灵活。所以我们没有直接让前端查询Flowable而是做了一层任务视图平台定时任务把待办数据从Flowable同步到自己的任务宽表里宽表冗余了Flowable任务ID、任务Key、流程实例ID、业务单号、表单标识、业务摘要、当前节点名、接收人、创建时间、优先级等字段。业务系统统一查这个宽表体验和性能都远超直查Flowable。任务操作方面除了基础的审批同意、驳回我们重点实现了加签、转办、委派、撤回。这四个操作本质都是修改Flowable任务办理人但细节差异很大。加签ADD_AND_APPROVE是当前任务继续保留、同时新增一个会签任务转办是把任务直接交给另一个人处理当前人不再是办理人委派是当前人把任务委派给另一个人被委派人处理后任务还会回到当前人撤回一般是发起人在流程还在第一个节点时主动把整个流程结束起来。这些操作我们都封装成平台接口业务系统不需要再自己调用TaskService去改办理人也就不容易出现办完任务后历史里看不到是谁处理的这种问题。4.4 权限模型从流程级到任务级权限设计直接决定平台能否被业务方接受。我们经过几轮调整最后沉淀了一套比较务实的权限模型分两层流程发起权限和任务处理权限。流程发起权限比较简单就是“谁能发起某类流程”的策略配置可以按部门、岗位、角色、用户甚至可以按业务数据规则来限制。我们把这部分做成了页面配置而不是写死在代码里。这样业务调整发起范围时不需要发版。任务处理权限复杂一些核心是解决“谁能看到这个待办、谁能处理这个待办”。之前裸用Flowable时有人通过候选组的方式配置待办候选人的判断逻辑分散在各处。平台的做法是统一在任务分配策略里管理任务创建时根据流程模型里预先配置的分单规则把任务分配给具体用户或候选组并在任务数据里写入允许操作的用户列表。后面做待办查询时直接按“处理人当前用户”或“当前用户在候选组列表里”过滤简单直接也方便做数据权限控制。4.5 事件扩展点让流程和业务系统解耦一个审批流程“审批通过后自动更新单据状态”这件事如果写在Flowable的监听器里那Flowable就和你业务系统强耦合了。平台的处理方式是提供标准的事件回调机制。我们在Flowable的监听器里只做一件事把事件抛到平台的消息管道里。比如任务创建、任务完成、流程结束、流程取消这些事件统一封装成标准消息体包含事件类型、流程实例ID、流程Key、任务ID、业务单号、操作人等字段然后推送给在平台上订阅了这个流程事件的回调地址。业务系统侧只需要提供一个接收回调的HTTP接口在配置中心里登记一下即可。这个设计把流程引擎和业务系统彻底解耦了。后面新的业务系统接入时不需要去改平台代码不需要再往Flowable里塞业务逻辑只需要注册回调就行。哪怕是改业务逻辑也不会造成流程实例运行中途找不到监听类的问题。4.6 监控与历史归档平台上线后的第一件事是把积压任务监控做起来。我们写了一个定时任务每隔5分钟统计ACT_RU_TASK里各流程节点的任务数量、停留时长超过阈值的就推送告警。这个告警此前救过一次紧急事故某个系统调用回调接口一直失败任务在“已办结但回调失败”的状态下堆积了几百条正是停留时长告警帮我们第一时间发现的。历史数据归档策略也得尽早订。我们按月份分区管理ACT_HI_ACTINST和ACT_HI_TASKINST这两张大表每个月定时把三个月前的明细数据迁移到历史库。同时借助Flowable自带的历史数据自动清理机制把不需要保留的流程定义级数据、已有归档副本的流程实例数据做异步清理。这块做好了数据库规模才能稳定住不会跑着跑着突然因为磁盘和慢查询出事。5. 关键设计细节与踩坑实录平台建设过程中有大量看似不起眼、但影响巨大的细节。这一节我把印象最深的几个单独拿出来讲都是实际踩过的坑希望能帮大家绕开。5.1 流程定义ID还是KEY一定要分清Flowable里有两个标识容易搞混流程定义Key和流程定义ID。Key是BPMN文件里process元素的id属性比如leaveProcess部署之后Flowable会生成一个带版本号的流程定义ID形如leaveProcess:1:25031004。很多调用场景要传流程定义ID比如按版本发布、按版本查询模型如果混用轻则查不到数据重则把流程部署到了错误版本。我们的统一策略是平台内部所有操作都以“流程Key 版本号”作为逻辑标识部署ID只在需要调用Flowable原生API时临时获取不落库、不传递。这样业务系统只跟平台的Key体系打交道版本歧义在平台层就消化掉了。5.2 业务单号与流程实例绑定必须用独立关联表很多教程里推荐用Flowable的businessKey来关联业务单号我们在早期也这么干过后来发现不行。原因是businessKey只能在发起时设置一次后续如果业务单号因为某种原因需要改变或者一个流程实例要关联多个业务单据businessKey就不够用了。我们最终采用了独立关联表方案。PROC_BIZ_REL表记录了流程实例ID、流程Key、业务主单据ID、业务扩展单据ID列表、创建时间。查询流程状态时先根据业务单号反查流程实例ID再查流程状态反过来的需求也同理。这张表是我们整个平台数据模型里承担压力最大的一张表一定要做好索引和分表规划。5.3 历史表膨胀不是等到慢了才处理Flowable的历史数据写入非常积极尤其ACT_HI_ACTINST几乎每个活动进出都记一条。高并发场景下这张表的增长速度超出很多人预期。我们曾经在生产上出现过ACT_HI_ACTINST达几千万行的情况导致所有带历史表查询的接口响应时间从几十毫秒变成几秒。两条处置经验分享一是从平台上线第一天就把归档任务写好不要等出了问题再补二是历史数据查询接口不要总是直查Flowable历史表可以定期把需要长期保留的流程快照数据冗余到自己的历史宽表里查询走宽表Flowable历史表只作为原始数据留存。这样既保留了数据完整性又保证了查询性能。5.4 上传BPMN文件的校验不能省我们对外开放模型上传功能后业务方经常从各种建模工具里导BPMN文件上来。有些文件的命名空间不规范有些引用了一些Flowable不支持的扩展属性甚至还有的XML在其他工具里能打开、Flowable解析就报错。平台做的校验包括三层一是XML格式的解析校验确保文件能被正常解析成文档对象二是BPMN语义校验检查是否存在孤立节点、未闭合网关等基础问题三是Flowable部署前的集成校验直接调用引擎的部署接口试部署一下部署成功才允许发布。虽然这个校验会多花几秒钟但省掉了大量上线后才发现模型错误的尴尬。5.5 任务查询的索引与缓存设计Flowable的ACT_RU_TASK在生产环境数据量不小待办查询如果不走索引全表扫描非常致命。我们观察下来以下三个查询场景必须建好索引按任务办理人查询、按流程实例ID查询、按任务Key和流程定义Key组合查询。Flowable的ACT_RU_TASK表默认有一些索引但不同数据库版本上的索引覆盖并不完全一致所以建好表之后最好由DBA结合真实慢查询日志把索引补一轮。另外流程定义本身是只读资产非常适合做JVM级缓存。我们把流程Key对应的最新部署ID、模型元数据都要缓存在平台进程内热流程发起时不再反复查询数据库。这个缓存命中率高、失效时机清晰只在流程部署新版本时刷新效果非常好。6. 常见问题排查速查表平台在线上跑了这段时间有几类问题反复出现。我整理了一个排查速查表按“现象、可能原因、排查思路、预防建议”的格式列出来方便团队各位直接参照。现象可能原因排查思路预防建议发起流程后待办里看不到任务任务创建后又被代码主动删掉或者任务分配给了候选组而当前用户不是候选成员查ACT_RU_TASK确认该流程实例是否有任务查平台事件流里任务创建事件是否正常发出任务分配统一走平台策略不裸调Flowable流程实例执行到某节点后不再往下走网关条件表达式没有分支命中或JavaServiceTask执行抛异常被吞掉查ACT_RU_EXECUTION当前停留的节点看平台异常日志是否有引擎执行错误网关条件要写兜底分支ServiceTask异常要抛出来并告警会签任务只产生了一个人的任务多实例的collection表达式写错或者输入变量没传对查流程发起时variables集合是否正确检查节点多实例配置多实例输入集合统一由平台注入不靠业务系统传菜名定时器事件不触发引擎时钟没有开启或执行节点上的服务实例没有运行查Flowable时钟配置查看定时节点所在服务是否存活定时任务单独跑在独立服务并配置进程守护流程审批完结但业务系统没有收到回调监听器抛异常被忽略或回调接口网络超时查平台事件表和回调重试记录确认回调地址可达回调必须配置重试机制和失败告警历史数据查询特别慢ACT_HI_ACTINST表过大索引缺失看慢SQL是否都命中历史表确认归档任务是否正常运行从上线第一天就启动归档查询走自定义历史宽表同一个单据被重复发起了流程前端重复点击或MQ重复投递查PROC_BIZ_REL是否同一businessId对应多个流程实例发起接口做幂等校验businessIdprocKey建唯一索引新发布流程模型后老流程实例跑挂老实例走到已删除的节点或引用了不存在的bean查老流程实例当前停在哪一步和分析新老模型差异发布新模型前做兼容性检查不允许删除仍有在途实例的节点这个表基本覆盖了我们日常运维中需要处理的80%问题。排查时记得先看现象发生在运行期还是流程定义期能少走很多弯路。7. 结合实际运维再说几点真心话写到最后我想分享一些个人在推进这件事时形成的体会。第一做统一流程平台最难的往往不是技术而是推动业务系统按规范接入。我们给业务方定的规矩是“平台提供能力但禁止绕过平台动引擎”。听起来像是对业务方的限制实际上反而帮他们省了很多事——不用自己维护流程代码、不用自己处理流程历史和权限只需对接平台的标准API。但前期的沟通量确实很大建议从简单增量的流程开始试点做出示范案例之后再推全量。第二流程平台的价值要在“运行三个月后”才能真正体现。初期业务系统会感觉平台多了一层联调多了一些成本看不到明显收益。真正跑起来之后统一待办、统一监控、权限集中、模型管理这些能力才逐步显现出价值。所以如果你们也在推进类似的事情给自己和团队多一点耐心关键节点放在上线后第一次大促或月度结算峰值时那时候平台的承压能力一目了然。第三扩展性要给后面留好口子。我们平台建设时最担心的是“Flowable有一天不能满足需求怎么办”。为此我们在引擎适配层做了模块化封装核心接口都定义在平台自己的服务里底层是Flowable还是其他引擎只影响适配层实现不影响上层业务。目前还没发生引擎替换但这个设计给了团队很大的安全感。第四平台化之后那些“清理历史数据”“监控积压任务”“巡检流程执行异常”之类的事情就不再是某个业务系统自己的事了而是平台团队的日常职责。这其实是一件好事当你从“把流程跑通”上升到“管理流程资产”时才能发现哪些流程长期没人用、哪些流程频繁超时、哪些流程的模型写得乱七八糟。流程本身也变成了需要治理的数字资产。这套方案做到现在平台已经稳定支撑了公司内部多个业务域的上百个流程每天承载数万次任务操作统一待办入口成为了大家日常工作必不可少的部分。如果你也正在从单点使用Flowable走向流程平台化的路上希望这篇总结能帮你对整体规划和细节设计有一个清晰的参考。别想着一步到位先圈定边界、统一入口、做好模型和权限的治理再从运行中逐步补齐监控、归档和扩展能力这条路走下来是踏实的。
阅读完成 · 觉得有帮助?