news 2026/9/18 4:24:45

Camunda 7 滚动更新(Rolling Update)测试套件深度解析:跨版本数据库兼容性验证的完整方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Camunda 7 滚动更新(Rolling Update)测试套件深度解析:跨版本数据库兼容性验证的完整方案

Camunda 7 滚动更新(Rolling Update)测试套件深度解析:跨版本数据库兼容性验证的完整方案

【免费下载链接】camunda-bpm-platformCamunda 7 CE is End of Life (EoL). Please check out Camunda 8 instead (https://github.com/camunda/camunda) or read about Camunda 7 Enterprise End of Life (https://camunda.com/blog/2025/02/camunda-7-enterprise-end-of-life-extension/) – Camunda 7 CE was a flexible framework for workflow and decision automation using BPMN and DMN.项目地址: https://gitcode.com/GitHub_Trending/ca/camunda-bpm-platform

导读

本文以 qa/test-db-rolling-update/README.md 为主线,深入剖析 Camunda BPM Platform 中用于验证跨小版本(minor version)数据库兼容性的滚动更新测试套件。该套件模拟真实生产环境中最常见的升级路径——旧版本引擎进程实例存活期间,数据库 schema 被新版本升级——并验证旧引擎操作升级后数据库时的正确性。读完本文,你将掌握该套件的五步工作流、四个 Maven 模块的职责划分、全部测试场景的覆盖范围,以及如何使用mvn/mvnw在任意支持的数据库上运行这套测试。

一、为什么需要滚动更新测试:场景与意义

Camunda 7 引擎的版本演进遵循"滚动升级"(rolling upgrade)原则:在生产环境中,旧版本($PREVIOUS)引擎和新版本($CURRENT)引擎会在同一套数据库上共存一段时间。旧引擎进程实例尚未结束,而数据库 schema 可能已经被新引擎的升级脚本修改。

这意味着,数据库需要同时满足两个方向的要求:

  • 前向兼容(forward compatible):新版本引擎可以读取旧版本引擎写入的数据(通过$PREVIOUS$CURRENT的 schema 升级脚本实现);
  • 后向兼容(backward compatible):旧版本引擎在升级后的 schema 上仍然可以继续运行、完成任务、查询数据。

滚动更新测试套件正是为此设计:它刻意让旧引擎在升级后的数据库上执行测试,从而验证后向兼容性——这是普通单元测试和集成测试无法覆盖的盲区。

从源码结构看,该套件由四个 Maven 模块组成(定义于 qa/test-db-rolling-update/pom.xml 的<modules>中),按执行顺序依次是:

模块职责
rolling-update-util共享的测试场景定义与工具类(TestFixture、场景类、常量)
create-old-engine用旧版本引擎创建数据(schema + 流程实例)
create-new-engine升级 schema,并用新版本引擎补充数据
test-old-engine用旧版本引擎执行全部验证测试

二、五步工作流:从旧引擎建库到旧引擎验证

README 用一个精炼的五步流程概括了整套机制($CURRENT指当前小版本,$PREVIOUS$CURRENT - 1):

  1. Create DB schema for$PREVIOUS:为旧版本创建完整的数据库 schema;
  2. Execute test setup with$PREVIOUSengine:使用旧版本引擎执行测试场景设置(部署流程、启动流程实例、写入历史数据等);
  3. Patch DB schema to$CURRENT:将数据库 schema 升级(patch)到当前版本;
  4. Execute test setup with$CURRENTengine:使用当前版本引擎执行补充的场景设置;
  5. Run tests with$PREVIOUSengine:最终用旧版本引擎运行全部测试,验证其对升级后数据库的兼容性。

其中步骤 3 与步骤 4 的顺序至关重要:schema 先升级、再由新引擎写入"新版本特性"数据,最终旧引擎必须能够正确读取和处理这些数据——这正是滚动升级场景下最易出问题的环节。

源码印证:新旧引擎入口类

步骤 2 与步骤 4 分别由两个main类驱动,它们都委托给共享的 TestFixture:

  • CreateOldEngineMain.java:调用TestFixture.main(new String[]{RollingUpdateConstants.OLD_ENGINE_TAG})
  • TestNewEngineMain.java:调用TestFixture.main(new String[]{RollingUpdateConstants.NEW_ENGINE_TAG})

新旧引擎通过 tag 区分,常量定义在 RollingUpdateConstants.java:OLD_ENGINE_TAG = "OLD"NEW_ENGINE_TAG = "CURRENT"。tag 会被拼入场景名称(如OLD.ProcessWithUserTaskScenario.xxx),供测试阶段按 tag 检索对应场景创建的数据。

三、场景设置(TestFixture):两个引擎版本各写什么数据

TestFixture.main() 展示了数据准备的完整逻辑:

  1. camunda.cfg.xml构建 ProcessEngine;
  2. 创建ScenarioRunner并注册通用场景(新旧引擎都会执行);
  3. 仅当 tag 为CURRENT(新引擎)时,额外注册三个"新版本专属"场景;
  4. 关闭引擎后,再从camunda.auth.cfg.xml构建第二个引擎,注册授权(authorization)场景。

通用场景(新旧引擎均执行)

ScenarioRunner.setupScenarios()依次注册了以下场景类(均在rolling-update-utilscenarios包下):

  • ProcessWithUserTaskScenario:含用户任务的流程;
  • ProcessWithAsyncServiceTaskScenario:异步服务任务;
  • ProcessWithUserTaskAndTimerScenario:用户任务 + 定时器;
  • DeploymentWhichShouldBeDeletedScenario:验证删除部署;
  • ProcessWithParallelGatewayScenario 与 ProcessWithParallelGatewayAndServiceTaskScenario:并行网关相关;
  • ProcessWithCallActivityScenario:调用活动(Call Activity);
  • ProcessWithMultiInstanceCallActivityScenario:多实例调用活动(注意源码包名中mulltiInstance为原样保留的拼写);
  • ProcessWithExternalTaskScenario:外部任务;
  • ProcessWithEventSubProcessScenario:事件子流程;
  • JobTimestampsUpdateScenario 与 IncidentTimestampUpdateScenario:Job 与 Incident 时间戳更新。

新引擎专属场景(仅CURRENTtag 执行)

if (RollingUpdateConstants.NEW_ENGINE_TAG.equals(currentFixtureTag)) { runner.setupScenarios(HistoryCleanupScenario.class); runner.setupScenarios(EmptyStringVariableScenario.class); runner.setupScenarios(SetRemovalTimeToProcessInstanceScenario.class); }
  • HistoryCleanupScenario:历史数据清理;
  • EmptyStringVariableScenario:空字符串变量;
  • SetRemovalTimeToProcessInstanceScenario:批量设置移除时间(Batch 操作)。

此外,第二个引擎(camunda.auth.cfg.xml)上注册了 AuthorizationScenario,覆盖授权(权限)数据的兼容性。

ScenarioRunner 的底层机制

场景的注册与执行依赖 qa/test-db-util 中的 ScenarioRunner:它通过反射扫描场景类中带@Deployment注解的方法完成流程部署(支持 classpath 资源与 BpmnModelInstance 两种方式),再扫描带@DescribesScenario注解的方法收集场景定义,最后按依赖关系(@ExtendsScenario)创建实例。场景名称统一为{tag}.{ClassName}.{scenarioName}格式,测试阶段依据该命名从数据库中精确检索。

四、Schema 升级:patch 与 upgrade 脚本的执行顺序

步骤 3 的实现位于 create-new-engine/pom.xml 的rolling-updateprofile 中,核心是sql-maven-plugintest-compile阶段按固定顺序执行的三个 SQL 批次:

  1. patch-previous-schema:应用旧版本($PREVIOUS)的累积 patch 脚本:
    • ${database.type}_engine_${previous.minor.version}_patch.sql
    • ${database.type}_identity_${previous.minor.version}_patch.sql
  2. upgrade-db:执行从旧版本到当前版本的小版本升级脚本:
    • ${database.type}_engine_${previous.minor.version}_to_${current.minor.version}.sql
    • ${database.type}_identity_${previous.minor.version}_to_${current.minor.version}.sql
  3. patch-current-schema:显式应用当前版本($CURRENT)的后续 patch(该执行默认留空,源码注释中给出了形如7.24.0_to_7.24.1.sql的扩展示例)。

SQL 脚本本体并非手工复制,而是通过maven-dependency-pluginorg.camunda.bpm.distro:camunda-sql-scripts的 test-jar 中解压到target/scripts-current目录。同时maven-antrun-plugin会"兜底"创建脚本占位文件——因为某个版本可能恰好没有数据库变更(对应_patch.sql_to_.sql文件不存在于发行包中的情况),保证构建不因文件缺失而失败。

版本号解析由build-helper-maven-plugin完成:create-new-engine/pom.xml中定义camunda.version.current=${project.version}(当前仓库为 7.24.0-SNAPSHOT)、camunda.version.previous=7.23.0,解析出的camunda.current.majorVersion/minorVersioncamunda.previous.majorVersion/minorVersion用于动态拼接上述 SQL 文件名。

五、执行测试:Maven 命令与数据库选择

README 给出的执行方式如下。

标准 Maven 命令

在项目根目录执行:

mvn clean install -Prolling-update,${DATABASE}

其中:

  • rolling-updateprofile 是套件的核心激活开关——只有激活它,四个模块中与滚动更新相关的插件执行和测试才会运行;
  • ${DATABASE}是目标数据库标识符,需要替换为实际值。

Maven Wrapper 命令

使用仓库自带的mvnw从项目根目录执行:

./mvnw clean install -f qa/test-db-rolling-update/pom.xml -Prolling-update,${database-id}
  • -f qa/test-db-rolling-update/pom.xml:显式指定套件自身的聚合 POM;
  • ${database-id}示例值为h2(内置数据库,无需外部依赖即可运行)。

数据库标识符的作用

${database-id}/${database.type}贯穿整个构建:它既决定了camunda-sql-scripts中解压的 SQL 脚本文件(${database.type}_engine_*.sql${database.type}_identity_*.sql)与drop脚本,也决定了测试连接的 JDBC 数据源(通过各模块资源目录中的配置文件)。Camunda 7 官方支持的数据库(如 h2、MySQL/MariaDB、PostgreSQL、Oracle、SQL Server 等)均可作为该参数取值,实际可用集合以 qa 目录 及camunda-sql-scripts发行包中的脚本清单为准。

构建阶段与插件的完整编排

各模块在rolling-updateprofile 下的执行时机汇总如下:

Maven 阶段create-old-enginecreate-new-enginetest-old-engine
generate-test-sourcesantrun 创建脚本占位、dependency 解压 SQL、build-helper 解析版本
test-compilesql-maven-plugin 依次执行 patch-previous → upgrade-db → patch-current
process-test-classesexec 运行CreateOldEngineMainexec 运行TestNewEngineMain
test/ 集成测试surefire 运行全部测试用例
post-integration-testsql-maven-plugin 执行 drop 脚本清理数据库

可以看到,create-old-enginecreate-new-engine通过 Maven 生命周期天然形成先后顺序,而test-old-engine的默认distroprofile 通过<skipTests>true</skipTests>跳过测试,只有在rolling-updateprofile 激活时才真正执行测试——这保证日常构建不会误跑需要特殊数据库编排的滚动更新用例。

六、测试用例:参数化双引擎验证

测试代码位于 test-old-engine 的测试目录,核心基类是 AbstractRollingUpdateTestCase.java:

@RunWith(Parameterized.class) public abstract class AbstractRollingUpdateTestCase { @Parameters(name = "{0} engine") public static Collection<Object[]> data() { return Arrays.asList(new Object[][] { {RollingUpdateConstants.OLD_ENGINE_TAG}, {RollingUpdateConstants.NEW_ENGINE_TAG} }); } @Parameter public String tag; @Rule public UpgradeTestRule rule = new UpgradeTestRule(); @Before public void init() { rule.setTag(tag); } }

关键设计:

  • 参数化运行:每个测试类都会以OLDCURRENT两个 tag 分别执行一遍(报告显示为 "OLD engine" / "CURRENT engine");
  • tag 驱动数据检索UpgradeTestRule依据当前 tag 定位对应引擎版本创建的场景数据,因此同一份测试代码既验证旧引擎在升级后数据库上的行为(OLDtag,本文核心目标),也验证新引擎行为(CURRENTtag,作为对照)。

测试用例全景

继承该基类的测试覆盖了与场景一一对应的验证点(目录与场景包结构对应):

类别测试类
用户任务 / 任务流转CompleteProcessWithUserTaskTest、CompleteProcessWithAsyncServiceTaskTest、CompleteProcessWithUserTaskAndTimerTest
网关 / 调用活动CompleteProcessWithParallelGatewayTest、CompleteProcessWithParallelGatewayAndServiceTaskTest、CompleteProcessWithCallActivityTest、CompleteProcessWithMultiInstanceCallActivityTest
外部任务 / 事件子流程CompleteProcessWithExternalTaskTest、CompleteProcessWithEventSubProcessTest
时间戳 / 历史清理 / 批量IncidentTimestampUpdateTest、JobTimestampsUpdateTest、HistoryCleanupTest、SetRemovalTimeToProcessInstanceTest
变量 / 部署 / 授权EmptyStringVariableTest、DeleteDeploymentTest、AuthorizationTest

其中时间戳类测试继承 AbstractTimestampUpdateTest,专门校验升级过程中 Job 与 Incident 表时间戳字段的迁移正确性——这是 schema 升级中最容易因类型转换或默认值变化而出错的细节。

环境清理

test-old-enginerolling-updateprofile 在post-integration-test阶段通过sql-maven-plugin执行camunda-sql-scripts中的 drop 脚本(${database.type}_engine_${project.version}.sql_identity_对应脚本)清理数据库,保证重复运行不会受残留数据影响;同时redirectTestOutputToFile将测试输出重定向到文件,便于在 CI 中归档排查。

七、套件的适用前提与限制

基于仓库现状,使用该套件时需注意以下几点:

  • 版本配对是硬编码的create-old-enginetest-old-engine通过camunda-bom锁定7.23.0create-new-engine使用camunda.version.previous=7.23.0、current 为构建版本7.24.0-SNAPSHOT。因此当前仓库中"旧引擎"固定为 7.23.0、"新引擎"固定为 7.24.x,验证的是这两个相邻小版本之间的滚动兼容性;
  • 依赖 camunda-sql-scripts 发行包:SQL 升级/清理脚本从org.camunda.bpm.distro:camunda-sql-scripts的 test-jar 解压而来,执行前需确保该构件可被 Maven 解析;
  • 社区版生命周期说明:根据 qa/test-db-rolling-update/pom.xml 中的描述,7.24.0 是 Camunda 7 社区版在 Maven Central 发布的最后一个版本,该套件不再随社区版发布新版本(扩展维护需转向企业版,仓库中亦注明 Camunda 7 CE 已进入 End of Life 阶段,新项目建议评估 Camunda 8)。

结语

滚动更新测试套件是 Camunda 7 保障升级安全性的关键基础设施:通过"旧引擎建库 → 新引擎升级 schema → 旧引擎回读验证"的闭环,它以最小成本捕获了跨版本数据库兼容性问题。理解其模块编排、tag 机制与 SQL 脚本执行顺序,不仅有助于你在本地复现升级验证(./mvnw clean install -f qa/test-db-rolling-update/pom.xml -Prolling-update,h2),也能为自研工作流引擎的升级测试体系设计提供可借鉴的范式。

【免费下载链接】camunda-bpm-platformCamunda 7 CE is End of Life (EoL). Please check out Camunda 8 instead (https://github.com/camunda/camunda) or read about Camunda 7 Enterprise End of Life (https://camunda.com/blog/2025/02/camunda-7-enterprise-end-of-life-extension/) – Camunda 7 CE was a flexible framework for workflow and decision automation using BPMN and DMN.项目地址: https://gitcode.com/GitHub_Trending/ca/camunda-bpm-platform

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/18 4:21:49

RTX 5060 海光 3490 Ubuntu 22.04 驱动与 CUDA 环境落地

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/18 4:21:33

Python协程与asyncio核心概念详解:事件循环与异步IO实战入门

刚把多线程和多进程折腾明白的兄弟&#xff0c;估计又要被一堆概念绕晕了。协程、异步IO、asyncio&#xff0c;这些词听着高端&#xff0c;其实解决的就是一个“程序跑得飞快但CPU却在空等”的问题。这篇是Python协程系列的第一篇&#xff0c;我们先把异步IO和asyncio的核心概念…

作者头像 李华
网站建设 2026/9/18 4:21:24

提示词工程实战:10个可复用的AI提示词技巧与模板库

每次接手一个新的AI落地项目&#xff0c;我都会先跟对方团队聊一个问题&#xff1a;“你们平时是怎么写提示词的&#xff1f;”得到的回答里&#xff0c;十有八九是“就是描述一下需求”或者“网上抄一个模板改一改”。这其实就是提示词工程和普通“聊天式提问”之间最本质的差…

作者头像 李华
网站建设 2026/9/18 4:20:46

openKylin Token中心免费Token申请与使用全攻略

最近这段时间&#xff0c;我身边不少搞AI应用、写自动化脚本的朋友都在抱怨同一个问题&#xff1a;Token又不够用了。有人是注册了一堆大模型平台的免费额度&#xff0c;结果真到跑测试、调prompt的时候&#xff0c;额度像流水一样哗哗往外淌&#xff1b;也有人是用了某个国内开…

作者头像 李华
网站建设 2026/9/18 4:17:17

DeepLabv3+图像分割实战:ASPP、损失函数与推理加速调参

做广告牌分割那会儿&#xff0c;我一开始用的是UNet&#xff0c;小目标还行&#xff0c;一到大幅面、细长结构的广告牌边缘就开始糊&#xff0c;边缘一圈毛刺怎么调都下不去。后来换成DeepLabv3&#xff0c;把输出步长压到8&#xff0c;ASPP的膨胀率按输入分辨率重新配了一遍&a…

作者头像 李华