✔️本专栏将从Camunda(卡蒙达) 7中的关键概念到实现中国式工作流相关功能。
✔️文章中只包含演示核心代码及测试数据,完整代码可查看作者的开源项目snail-camunda
✔️请给snail-camunda 点颗星吧
通常业务流程是长期运行的,所以流程实例可能会持续几天或者几个月。不可避免的是即使仍有正在运行的实例,我们也可能需要变更流程定义。Camunda流程引擎支持以下情况:
在act_re_procdef表中可以看到,同一个流程定义Key可以对应多个版本,每个版本有唯一的流程定义id
Key就是xml中的id
当发起流程实例时如果是通过流程定义Key,则会使用流程定义的最新版本
如果通过流程定义Id则会使用对应的版本
可以通过流程定义的Version Tag属性设置
通过标签来查询定义列表
List definitionList = repositoryService.createProcessDefinitionQuery()
.versionTag("1-1")
.list();
当然也可以使用模糊查询
List definitionList = repositoryService.createProcessDefinitionQuery()
.versionTagLike("1-%")
.list();
默认情况下每当部署新版本的流程定义时,运行的现有流程实例 在以前的版本上不受影响。如果想把这部分流程实例也应用在最新版本上,则可以使用迁移来完成。迁移包括两个部分:
迁移计划由一组迁移指令组成,这些指令实质上是两个流程定义的活动之间的映射。它将源流程定义的活动映射到目标流程定义的活动。迁移指令确保源活动的实例被迁移到目标活动的实例中。当有针对所有活动源活动的说明时,迁移计划就完成了。
迁移指令的目的是映射语义上等价的活动。因此,迁移尽可能少地干扰活动实例状态,从而确保无缝转换。比如迁移后的用户任务实例不会被重新分配,从受让人【assignee】的角度来看,迁移大部分是透明的,因此在迁移之前开始的任务必须在迁移后能够顺利完成。
开始演示:首先设计一个流程定义并发起一条流程实例
修改刚刚的流程定义并重新部署
新增迁移接口
@PostMapping("/migrate")
public void migrateProcessInstance(@RequestBody MigrationRequest requestParam){
//指定迁移计划
MigrationPlan migrationPlan = runtimeService
.createMigrationPlan(requestParam.getSourceProcessDefinitionId(), requestParam.getTargetProcessDefinitionId())
.mapActivities("Activity_02y74m7#multiInstanceBody", "Activity_02y74m7#multiInstanceBody")
.mapActivities("Activity_02y74m7", "Activity_02y74m7")
.build();
//执行计划
runtimeService.newMigration(migrationPlan)
.processInstanceIds(requestParam.getProcessInstanceIds())
.execute();
}
接口请求参数如下:
@Data
public class MigrationRequest {
/**
* 需要迁移的流程定义id
*/
private String sourceProcessDefinitionId;
/**
* 迁移目标流程定义id
*/
private String targetProcessDefinitionId;
/**
* 需要迁移的流程实例id集合
*/
private List processInstanceIds;
}
迁移计划在执行之前会进行验证,以确保它可以应用于特定的流程实例。
迁移成功后流程实例已挂在新版本下了
实际上迁移的定义和目标定义中所有相同的活动都不需要手动指定。只需要明确指定出活动id不相同的迁移,所以上述迁移代码可以简化为
@PostMapping("/migrate")
public void migrateProcessInstance(@RequestBody MigrationRequest requestParam){
//指定迁移计划
MigrationPlan migrationPlan = runtimeService
.createMigrationPlan(requestParam.getSourceProcessDefinitionId(), requestParam.getTargetProcessDefinitionId())
.mapEqualActivities()
// .mapActivities("Activity_02y74m7#multiInstanceBody", "Activity_02y74m7#multiInstanceBody")
// .mapActivities("Activity_02y74m7", "Activity_02y74m7")
.build();
//执行计划
runtimeService.newMigration(migrationPlan)
.processInstanceIds(requestParam.getProcessInstanceIds())
.execute();
}
如果执行侦听器需要某些变量的存在才能正常执行,但该变量在源进程定义的实例中不存在,那就可以选择跳过监听器
runtimeService.newMigration(migrationPlan)
.processInstanceIds(processInstanceIds)
.skipCustomListeners()
.skipIoMappings()
.execute();
1、数据一致性
流程实例包含特定于流程实现方式的变量等数据。验证不能确保这些数据在目标流程定义的上下文中是有用的。
2、对象变量的序列化问题
如果是在不同的应用程序之间迁移,可能会出现Object变量在目标应用程序中不存在的Java类的情况。这一点流程引擎是不会去验证的。