前阵子帮一个老项目接 Flowable,需求听起来很简单:业务表继续留在主库里,流程引擎那几十张 ACT_ 开头的表放到独立数据源,并且 PostgreSQL 环境下还得落到指定 schema 里。结果从配置到跑通整整折腾了两个下午,期间踩过的坑包括但不限于:引擎把表建到了 public schema、多数据源事务互相串、以及被一个看起来像 Flowable 报错、实际是 API 校验的 invalid schema 错误误导了半天。这篇就把这段实战经验完整复盘一遍,从多数据源装配、指定 Schema 的原理,到常见的翻车现场和排查思路,一次性讲透,适合正在做 Flowable 集成、或者准备把工作流引擎从业务库中隔离出来的同学参考。
1. 场景设定与整体设计思路
1.1 为什么业务库和数据源必须分离
Flowable 作为 Java 生态里最主流的 BPMN 工作流引擎之一,开箱即用确实方便,但它默认行为很“霸道”:一旦你把flowable-spring-boot-starter-process引入工程,它就会自动寻找容器里的主数据源,把 ACT_GE_、ACT_RU_、ACT_HI_、ACT_ID_ 这几大类几十张表全部建进去。
如果你在项目初期就把流程表和业务表混在同一个库,前期开发没感觉,到了后面会非常难受:
- 备份恢复很被动。业务数据天天在变,流程历史数据也在暴涨,混在一起备份,要么备份文件巨大,要么想单独恢复某张业务表时被 ACT_HI_ACTINST 这种大表拖累。
- 权限粒度没法控制。DBA 希望应用账号只能读写业务表,流程引擎的账号单独管理,混库以后很难实现。
- 迁移和发布有风险。业务库做结构变更、分库分表的时候,引擎表会跟着受影响,一旦误操作,整个流程引擎直接瘫掉。
- 性能互相干扰。流程引擎大量写入 ACT_HI_ 历史表,业务报表查询也在跑,同一个数据库实例和连接池里互相争抢资源。
所以把 Flowable 独立出来,不只是“多配一个数据源”这么简单,本质上是把工作流引擎当成一个独立的基础设施来对待,和业务系统之间只通过 API 交互,底层数据完全隔离。
1.2 三种多数据源方案怎么选
我整理了一下,常见的方案其实有三种,各有适用场景:
| 方案 | 隔离程度 | 配置复杂度 | 适用场景 |
|---|---|---|---|
| 独立数据库实例 | 最高,物理隔离 | 高,需单独维护实例 | 大型系统、强隔离要求、跨团队运维 |
| 同实例独立库/独立 Schema | 中高,逻辑隔离 | 中,配置相对简单 | 大多数中大型单体/微服务项目 |
| 同库表前缀隔离 | 低,仅表名区分 | 低 | 小项目、快速原型、实在没有数据库权限 |
方案三用的是spring.flowable.table-prefix这个配置,让引擎表带上前缀,比如FLW_ACT_GE_PROPERTY。它虽然省事,但业务库里的表还是混在一起,前面说的备份、权限、性能问题一个都没解决。
方案一物理隔离最干净,但一般公司没那么多数据库实例资源。折中下来,绝大多数项目最合理的方案就是方案二:同一个 MySQL 实例里建一个独立 database,或者同一个 PostgreSQL 实例里建一个独立 schema,然后给 Flowable 单独配一个数据源账号。这也正是我这次实战采用的方案。
1.3 指定 Schema 到底在解决什么问题
很多人第一次看到databaseSchema这个配置会懵,其实“Schema”这个概念在不同的数据库里含义不太一样:
- MySQL:Schema 基本等同于 Database。你执行
CREATE DATABASE flowable_db,等于创建了一个 schema,表名完整写法就是flowable_db.act_ge_property。 - PostgreSQL:Schema 是数据库内部的一层命名空间,一个数据库可以有好几个 schema,默认情况下表会建到
public这个 schema 里,完整写法是flowable.act_ge_property。 - Oracle:一个用户对应一个 Schema,权限天然隔离,这个其实是 Oracle 的设计好处。
- SQL Server:Schema 是数据库内的命名空间,默认
dbo。
Flowable 里的databaseSchema配置,就是告诉引擎“你建表和读写表的时候,给我的表名加上哪个前缀”。比如设置成flowable,生成的 SQL 就会变成select * from flowable.act_ru_execution。对于 MySQL,由于 schema 就是数据库名,直接在 JDBC URL 里带上库名就行,databaseSchema填不填影响不大;但对于 PostgreSQL,如果不指定当前 schema 或者不设置databaseSchema,引擎就会老老实实找默认的public,然后你会在public里看到一堆 ACT_ 表,这就是很多人踩的第一个坑。
2. 前置准备与关键配置项
2.1 版本搭配参考
Flowable 的版本和 Spring Boot 的版本强相关,配错版本很容易出现莫名其妙的兼容性问题。我这次用的是 Spring Boot 2.7 搭配 Flowable 6.7.2,这是目前比较稳的组合:
| Spring Boot 版本 | Flowable 版本 | JDK | 说明 |
|---|---|---|---|
| 2.7.x | 6.7.2 或 6.8.x | 8/11/17 | 经典组合,资料最多,最稳妥 |
| 2.7.x | 6.6.0 | 8/11 | 老项目常见,升级需注意 |
| 3.x | 7.0.0+ | 17 | 新版引擎,包结构和配置有调整 |
| 3.2.x+ | 7.1.0+ | 17/21 | 新特性多,但踩坑资料相对少 |
有个点必须注意:Flowable 6 和 7 的某些 API 有变化,而且数据库表结构也不同。如果你从 5.x 直接升 6.x,不能指望database-schema-update: true帮你自动完成,版本跨度太大时就得跑官方迁移脚本。所以生产环境里,Flowable 引擎 JAR 版本和数据表里ACT_GE_PROPERTY记录的 schema.version 要保持一致,这个后面避坑章节会展开讲。
2.2 数据库实例与账号权限准备
我这次是 PostgreSQL 环境,需要单独建一个 schema 和一个专用账号:
-- 进入 flowable_db 数据库后执行 CREATE SCHEMA IF NOT EXISTS flowable AUTHORIZATION flow_user; -- 创建专用账号,只管理 flowable 相关对象 CREATE USER flow_user WITH PASSWORD 'flow_pass'; GRANT USAGE, CREATE ON SCHEMA flowable TO flow_user; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA flowable TO flow_user; GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA flowable TO flow_user; ALTER DEFAULT PRIVILEGES IN SCHEMA flowable GRANT ALL ON TABLES TO flow_user; ALTER DEFAULT PRIVILEGES IN SCHEMA flowable GRANT ALL ON SEQUENCES TO flow_user;如果是 MySQL,就简单一些:
CREATE DATABASE flowable_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; CREATE USER 'flow_user'@'%' IDENTIFIED BY 'flow_pass'; GRANT ALL PRIVILEGES ON flowable_db.* TO 'flow_user'@'%'; FLUSH PRIVILEGES;权限这里有个容易忽略的地方:如果你设置了database-schema-update: true,引擎启动时会自己去建表、加索引,那么数据库账号必须拥有 DDL 权限(CREATE、ALTER、INDEX)。如果公司安全规范不允许应用账号有 DDL 权限,那就得先手动执行 Flowable 提供的建表脚本,然后把database-schema-update设为false,只保留 DML 权限。
2.3 Flowable 核心配置项逐个说清
配置 Flowable 时主要围绕这几个参数,弄明白参数背后的逻辑,比死记配置语句有用得多:
| 配置项 | 可选值 | 作用 |
|---|---|---|
spring.flowable.database-schema-update | true/false/create-drop | 是否自动建表/升级表结构 |
spring.flowable.database-schema | 字符串 | 指定引擎表所在 Schema,PG 下尤其关键 |
spring.flowable.table-prefix | 字符串 | 表名前缀,比如FLW_,用于同库隔离方案 |
spring.flowable.history-level | none/activity/audit/full | 历史数据记录粒度,直接影响 ACT_HI_ 表数据量 |
spring.flowable.async-executor-activate | true/false | 是否启动异步执行器处理定时任务、异步消息 |
关于database-schema-update,网上很多人直接写true图省事,我建议生产环境谨慎。true的意思是“没有表就建,字段缺了就补”,听起来很智能,但引擎升级时它不会帮你做破坏性变更,遇到大版本切换该报错还是报错。而且一旦给了 DDL 权限,万一代码里有人手滑把databaseSchemaUpdate改掉,生产库结构会被自动改动,风险很大。我的习惯是:开发环境开true,测试和生产环境用官方 SQL 脚本手动建表,然后设false。
3. 从零到一:多数据源与指定 Schema 的完整落地
3.1 用 ConfigurationProperties 装配两个 DataSource
先看最终的application.yml,多数据源的思路是给业务库和 Flowable 库各自定义一组spring.datasource.*配置,用自定义前缀区分:
spring: datasource: business: driver-class-name: org.postgresql.Driver jdbc-url: jdbc:postgresql://192.168.1.10:5432/business_db?currentSchema=business&stringtype=unspecified username: bus_app password: bus_pass hikari: pool-name: BusinessPool maximum-pool-size: 20 minimum-idle: 5 flowable: driver-class-name: org.postgresql.Driver jdbc-url: jdbc:postgresql://192.168.1.10:5432/business_db?currentSchema=flowable&stringtype=unspecified username: flow_user password: flow_pass hikari: pool-name: FlowablePool maximum-pool-size: 10 minimum-idle: 2 flowable: database-schema-update: true database-schema: flowable history-level: audit async-executor-activate: true这里有一个很有迷惑性的细节:业务库和 Flowable 库可以不在同一个数据库实例上,我这个例子里 Flowable 的 URL 特意写的是business_db?currentSchema=flowable,意思是“同一个 PostgreSQL 实例、同一个数据库内,使用 flowable 这个 schema”。如果你更希望物理分开,那 Flowable 的jdbc-url就指向另一个数据库实例,原理完全一样。
注意 PG 连接串里的currentSchema=flowable,这个参数非常关键。PostgreSQL JDBC 驱动通过它来设置连接默认搜索路径,连接建立之后,不带 schema 前缀的表名就会先去flowable这个 schema 里找。配合stringtype=unspecified,可以避免某些情况下字符串类型被错误推断的问题,算是 PG 连接 Flowable 的老经验了。
然后定义数据源 Bean,两个数据源必须区分清楚谁是主:
import com.zaxxer.hikari.HikariDataSource; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import javax.sql.DataSource; @Configuration public class MultiDataSourceConfig { @Bean @Primary @ConfigurationProperties(prefix = "spring.datasource.business") public DataSource businessDataSource() { return DataSourceBuilder.create() .type(HikariDataSource.class) .build(); } @Bean @ConfigurationProperties(prefix = "spring.datasource.flowable") public DataSource flowableDataSource() { return DataSourceBuilder.create() .type(HikariDataSource.class) .build(); } }关键在于@Primary注解必须放在业务数据源上。Spring Boot 里的自动配置、MyBatis、JPA 这些组件,默认情况下拿到的是唯一的或带@Primary的数据源。我们希望业务框架仍然使用业务库,所以主数据源必须是业务库,Flowable 这个特殊数据源则由后面专门的配置类去引用。
有个小提示:使用DataSourceBuilder时配置项要写jdbc-url而不是url,因为 HikariCP 内部的真实属性名是jdbcUrl,Spring Boot 的宽松绑定会把jdbc-url映射过去。如果写成url,启动时大概率会报“DataSource 属性绑定失败”。
3.2 通过 ProcessEngineConfigurationConfigurer 接管引擎数据源与事务
有了两个数据源 Bean 之后,重点来了:怎么让 Flowable 引擎不要用主数据源,而是用flowableDataSource?
网上很多教程会让你排除FlowableAutoConfiguration,然后手动创建ProcessEngine、各个 Service Bean,这个方案能行但代码量很大,而且容易漏。其实官方早就提供了更优雅的口子:ProcessEngineConfigurationConfigurer。
这个接口的作用是在引擎配置对象构建完成、但 ProcessEngine 还没创建之前,给你一个修改配置的机会。我们可以在这个回调里把数据源和事务管理器换成 Flowable 专用的:
import org.flowable.spring.ProcessEngineConfigurationConfigurer; import org.flowable.spring.SpringProcessEngineConfiguration; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.transaction.PlatformTransactionManager; import javax.sql.DataSource; @Configuration public class FlowableEngineConfig { @Bean public ProcessEngineConfigurationConfigurer flowableEngineConfigurer( @Qualifier("flowableDataSource") DataSource flowableDataSource, @Qualifier("flowableTxManager") PlatformTransactionManager flowableTxManager) { return new ProcessEngineConfigurationConfigurer() { @Override public void configure(SpringProcessEngineConfiguration config) { config.setDataSource(flowableDataSource); config.setTransactionManager(flowableTxManager); config.setDatabaseSchema("flowable"); config.setDatabaseSchemaUpdate("true"); config.setHistoryLevel(HistoryLevel.AUDIT); config.setAsyncExecutorActivate(true); } }; } }setDataSource不用多解释,关键是setTransactionManager。Flowable 与 Spring 整合后,Service 层操作的事务边界是由PlatformTransactionManager控制的,如果你不指定,引擎会去 Spring 容器里找,但此时容器里有业务库和 Flowable 库两个事务管理器,很容易选错。所以必须在配置里明确告诉引擎:你的事务管理器是绑定 Flowable 数据源的那个。
setDatabaseSchema("flowable")的作用是和currentSchema=flowable双保险。引擎建表和读写 SQL 时,会尝试给表名加上 schema 前缀。对于 PostgreSQL 来说,如果没有这个配置,即使 JDBC URL 里带了currentSchema,某些版本的 Flowable 在 DDL 阶段仍可能把表建到public,这个后面避坑章节再展开。
3.3 指定 Schema 的几种实操姿势与底层原理
关于“指定 Schema”,我实际用下来有三种姿势,分别适用不同场景:
姿势一:JDBC URL 参数指定(推荐)。
PostgreSQL 用currentSchema,这个参数由驱动层设置连接默认搜索路径;MySQL 则直接把库名写在 URL 里。这种方式在连接层面就锁定了 schema 范围,最可靠。比如jdbc:postgresql://host:5432/business_db?currentSchema=flowable,连接建立后,未加前缀的ACT_RU_EXECUTION会优先在flowableschema 里解析。
姿势二:Flowable 配置属性指定。
spring.flowable.database-schema=flowable或者代码里config.setDatabaseSchema("flowable")。这个属性会被引擎用来在 DML/DDL 语句中拼接 schema 前缀,例如生成的 SQL 会变成insert into flowable.act_ru_execution(...)。注意 MySQL 下如果填了 schema 名,务必和 URL 里的库名保持一致,否则可能出现flowable_db.act_ge_property这种双重前缀的 SQL。
姿势三:SQL 里显式 set search_path。
这个往往被忽略,但在排查问题时很好用。数据库侧执行:
ALTER ROLE flow_user IN DATABASE business_db SET search_path TO flowable, public;这属于数据库层面的默认设置,相当于给这个角色在连接时自动执行SET search_path。如果应用配置没法轻易改,用这个方式也能解决 PG 下 schema 匹配问题。
三种姿势的背后原理是同一个:Flowable 在生成 SQL 时,表名最终要能在数据库里唯一解析。要么驱动层帮你想好默认 schema,要么引擎层主动拼前缀,两者至少有一个生效,否则必然落到public。
3.4 事务边界要分清:业务管理器与流程管理器的分工
多数据源的难点不只是数据源本身,事务管理器是另一个很容易炸的地方。我们最终在容器里要有两个PlatformTransactionManager:
@Bean @Primary public PlatformTransactionManager businessTxManager( @Qualifier("businessDataSource") DataSource businessDataSource) { return new DataSourceTransactionManager(businessDataSource); } @Bean public PlatformTransactionManager flowableTxManager( @Qualifier("flowableDataSource") DataSource flowableDataSource) { return new DataSourceTransactionManager(flowableDataSource); }业务代码里凡是用@Transactional的地方,默认会走businessTxManager,因为它有@Primary。而引擎内部的 Service 调用走的是flowableTxManager,因为我们在ProcessEngineConfigurationConfigurer里显式指定了。
实际开发中容易犯的错误是:在一个业务事务里同时操作业务表和 Flowable 服务,比如:
@Transactional public void createOrderAndStartProcess() { orderMapper.insert(order); runtimeService.startProcessInstanceByKey("orderProcess"); }这段代码乍一看没问题,但它隐含了一个大坑:业务事务和流程引擎事务是两个独立事务,orderMapper.insert提交失败时,流程实例可能已经启动了,反之亦然。多数据源本身不具备分布式事务能力,不要把跨库操作硬塞进一个@Transactional里。真需要原子性,要么引入 Atomikos 这类 XA 事务方案,要么用本地消息表加补偿任务,从架构层面规避。
4. 实战避坑:最常见的五个翻车现场
4.1 建表失败:先分清“数据库 Schema”还是“API Schema”
搜索 Flowable schema 相关报错时,你可能会搜到形如:api error: 400 invalid schema for function 'artifact': "^(?!.*$)[^\p{cc}\p{cf}\p{zl}\p{zp}\"\./[\]]{1,200}$" is not a "regex"这样的错误。我一开始也以为是 Flowable 的表结构校验报错,后来仔细一看完全不是一回事。
这种报错的典型特征很明显:带api error、400、function,并跟着一串正则表达式。它通常来自 API 网关或者 AI 代理工具,是“函数参数校验 schema”(一般是指 JSON Schema)定义不合法,和数据库 schema 没有半毛钱关系。Flowable 里的 schema 永远是指数据库里的命名空间,报错形式一般是 SQLState、JDBC 异常,或者org.flowable.common.engine.api.FlowableException开头的引擎异常。
所以排查第一步,先看错误类型。数据库 schema 跑偏的报错,核心信息里会有表名和 schema 名,比如:
ERROR: schema "flowable" does not exist或者:
Unknown database 'flowable_db'这类才是 Flowable 数据源配置的问题。看到一个 400 加一堆正则的报错,先去检查你的 HTTP 接口定义和工具参数格式,不要在 Flowable 配置里浪费时间。
4.2 表建到了默认库/默认 Schema
这是多数据源配置里出现频率最高的问题,表现是:业务系统正常启动,ACT_ 表也建出来了,但出现在public(PG)或者业务库(MySQL)里,而不是预期的 schema。
常见原因有三个:
原因一:JDBC URL 没带 schema 参数。PostgreSQL 下如果 URL 没写currentSchema,配置里又没设置databaseSchema,引擎会用数据库默认的public。解决方式就是前面说的,URL 加currentSchema,配置里再补setDatabaseSchema。
原因二:@Primary放错了位置。如果flowableDataSource不小心被加了@Primary,其他框架会优先用它,业务 SQL 全部跑到了流程库;更隐蔽的是,某些自动配置判断主数据源时也会取到 Flowable 数据源,导致引擎加载的构造配置混乱。
原因三:多个ProcessEngineConfigurationConfigurer互相覆盖。如果项目里之前有人写过一个 configurer 把dataSource设成了主数据源,而你又新增了一个 configurer 设置流程数据源,Bean 的执行顺序不确定,后执行的那个会覆盖前一个。这种问题特别隐蔽,建议先全局搜一下有没有其他ProcessEngineConfigurationConfigurer实现。
排查时用一条 SQL 就能确认表到底建到了哪:
-- MySQL SELECT table_schema, table_name FROM information_schema.tables WHERE table_name LIKE 'ACT\_%'; -- PostgreSQL SELECT table_schema, table_name FROM information_schema.tables WHERE table_name LIKE 'ACT\_%';如果结果里 schema 不是预期值,先把两处配置(URL + databaseSchema)都改对,再删掉建错的表重新启动。
4.3 schema.version 不匹配
另一个高频报错是启动时抛类似这样的异常:
org.flowable.common.engine.api.FlowableException: Could not find a valid Flowable database version或者:
Flowable database schema version mismatch这个错误的根源是ACT_GE_PROPERTY表里记录了schema.version,引擎启动时会拿这个值和当前 JAR 包里的版本做比对。常见场景是:老项目升级 Flowable JAR 版本,但数据库表没有跟着升级;或者 pom 里同时引入了多个 Flowable 模块,版本号不一致。
处理方式很直接:
- 先检查 pom 里所有
org.flowable相关依赖版本是否一致,统一用<flowable.version>属性管理。 - 小版本升级(比如 6.7.1 到 6.7.2),设
database-schema-update: true让它自动升级。 - 跨大版本(6.x 到 7.x),不要指望自动升级,先用官方升级脚本,或者对比
ACT_GE_PROPERTY中的 schema.version 与目标版本,按官方文档执行迁移。
这里还要提醒一句:别为了绕过版本检查把ACT_GE_PROPERTY里的版本号手工改掉,数据库结构和引擎代码不匹配,后面会冒出一堆字段不存在、存储过程调用失败的问题,远比版本检查报错难查。
4.4 多数据源事务串了导致写错库
这类问题表现特别诡异:业务代码里用@Transactional调用流程引擎服务,结果流程数据写到了业务库;或者反过来,流程执行过程中把业务表数据搞进去了。
从原理上讲,这通常是事务管理器选错了。DataSourceTransactionManager绑定的是具体哪个DataSource,它负责的 Connection 就是从那个数据源拿的。如果引擎的 transactionManager 没显式设置,Flowable 的 Spring 整合代码会尝试从容器中找一个事务管理器,而容器里有多个时,很可能拿到带@Primary的业务事务管理器。引擎拿着业务事务管理器,事务同步时绑定的资源是业务数据源的,但引擎 Service 内部拿连接时又去 flowableDataSource 获取,两边对不上,写库就乱了。
解决办法就是 3.2 节的做法:在ProcessEngineConfigurationConfigurer里显式setTransactionManager(flowableTxManager)。配置完之后,可以通过一个简单的自检接口确认:
@Autowired @Qualifier("flowableTxManager") private PlatformTransactionManager flowableTxManager; @Autowired private ProcessEngine processEngine; public void check() { SpringProcessEngineConfiguration config = (SpringProcessEngineConfiguration) processEngine.getProcessEngineConfiguration(); System.out.println("Engine DataSource = " + config.getDataSource()); System.out.println("Engine TxManager = " + config.getTransactionManager()); System.out.println("Engine schema = " + config.getDatabaseSchema()); }把这三样打出来,数据源和事务管理器是不是 Flowable 专用的,一眼就能看出来。
4.5 连接池配置不当导致引擎启动假死
最后一个坑比较隐蔽,表现是应用启动日志停在“Initializing process engine...”很久,然后超时失败,或者偶尔启动成功但异步任务一多就大量报错。
常见原因是 Flowable 数据源的连接池maximum-pool-size设置得太小。Flowable 的异步执行器会在线程池里跑定时任务、消息任务,一个事务就要占用一个连接。如果连接池上限是 1,引擎初始化时建表事务和异步任务初始化并发抢连接,就会出现死等。
另外,PostgreSQL 下如果 schema 权限不对,引擎创建表时可能反复重试,也会表现为启动假死。我见过一个案例,GRANT USAGE忘了给,启动日志只留下一句“Unable to obtain connection from database”,排查半天才发现是权限问题。
建议 Flowable 独立连接池至少 10 起步,异步任务多的项目给到 20 也不过分。同时把 HikariCP 的pool-name分别命名,启动时看到BusinessPool和FlowablePool各自 Start completed,就能确认两个连接池都起来了。
5. 日常维护与性能优化建议
5.1 独立连接池参数怎么给
多数据源配置完成只是开始,连接池参数直接影响引擎稳定性。我的经验是 Flowable 连接池不能照抄业务连接池,因为它有异步执行器,工作线程数量和数据库连接数强相关。
| 参数 | 建议值 | 说明 |
|---|---|---|
maximum-pool-size | 10 ~ 20 | 异步执行器线程数 + 预留余量 |
minimum-idle | 2 ~ 5 | 连接数超过活跃数较多时,可以设小减少空闲占用 |
connection-timeout | 3000 ~ 5000 | 取连接等待上限,任务量大时避免线程无限等待 |
validation-timeout | 1000 ~ 3000 | 连接校验超时,PG 下建议配合connection-test-query |
pool-name | 自定义 | 区分日志,方便观察哪个连接池出问题 |
Flowable 异步执行器的线程配置一般不用动,但如果项目里定时流程任务特别多,可以调整:
spring: flowable: async-executor-core-pool-size: 8 async-executor-max-pool-size: 16 async-executor-keep-alive-time: 30注意async-executor-core-pool-size和连接池maximum-pool-size之间要有合理的比例关系,线程数多于连接数时,多出来的线程都在等待拿连接。
5.2 历史数据增长与清理
流程引擎跑久了,ACT_HI_ACTINST、ACT_HI_TASKINST、ACT_HI_PROCINST这几张历史表的增长速度会超出预期。如果你的业务并不需要完整的过程审计,history-level没必要设成full,audit一般就够用了。
如果历史数据已经很大,可以用定时任务按条件清理,但要注意删除顺序,先删子表再删主表。示例 SQL:
DELETE FROM act_hi_actinst WHERE proc_inst_id_ IN ( SELECT id_ FROM act_hi_procinst WHERE start_time_ < now() - interval '180 days' ); DELETE FROM act_hi_taskinst WHERE proc_inst_id_ IN ( SELECT id_ FROM act_hi_procinst WHERE start_time_ < now() - interval '180 days' ); DELETE FROM act_hi_procinst WHERE start_time_ < now() - interval '180 days';这类清理建议在业务低峰期执行,删除大量记录时注意控制批次,避免把流程库的 WAL 撑爆。
5.3 备份、监控和发布注意事项
多数据源隔离的好处,在做备份和监控时体现得最明显。PostgreSQL 下只备份流程 schema:
pg_dump -h host -p 5432 -U flow_user -d business_db -n flowable -F c -f flowable_backup.dumpMySQL 下直接指定库名:
mysqldump -h host -u flow_user -p flowable_db > flowable_backup.sql监控方面重点关注三件事:ACT_RU_EXECUTION有没有异常积压的未完成流程、ACT_RU_JOB里错误重试的任务数量、以及连接池活跃连接数曲线。这几个指标能提前暴露流程引擎的大多数问题。
发布的时候还有个细节:业务系统发版时,尽量让 Flowable 引擎的database-schema-update保持稳定,不要在测试环境开true、生产环境设false,两套配置不一致,很容易造成“测试好好的,生产缺字段”的尴尬。引擎版本升级要单独排期,先备份,再执行升级脚本,最后替换依赖发版。
回到开头说的那个项目,折腾完这轮多数据源配置,我最大的体会是:Flowable 多数据源本身不难,难的是把“数据源”、“事务管理器”、“Schema”这三件事绑定在一起。大部分报错看起来像玄学,其实是配置对象之间没有对上号。如果你正卡在类似问题上,优先检查三件事:引擎到底用了哪个 DataSource、哪个 TransactionManager、databaseSchema是不是为空。把这三个值打印出来,问题基本就摊在桌面上了。项目里如果还有第二套 Flowable 环境或者流程引擎将来要拆分出去,这套配置思路也能直接复用,无非是多加一组数据源配置,把 schema 再拆一个出来而已。