Camunda 补偿事件、事务子流程、分布式事务一致性
总结
- 补偿事件只有当任务成功执行后才有可能触发;
- 事务子流程有取消事件,边界必须要有中断取消事件;
- 事务子流程只有触发取消事件,补偿事件才会触发;
- 事务子流程边界中断错误事件并不会触发补偿事件;
- 报异常的任务非数据库ACID事务时,需额外写逻辑回滚。报异常的任务不会触发补偿事件,当前任务异常技术上会ACID事务回滚。比如当前任务Http Rest操作或文件读写操作,此时补偿事件不会触发,之前创建的文件会一直存在;
- 子流程中有补偿事件子流程时,外部补偿结束事件触发子流程中的补偿事件子流程。子流程中没有补偿事件子流程时,外部补偿结束事件会触发子流程中所有任务的补偿事件;
- 取消事件 只会在事务子流程中;
- 补偿事件任务 后面不能有其他任务;边界不能添加其他事件;
- 补偿事件任务 也有可能报异常,不能通过边界错误事件捕获,只能系统报出(流程中断);
- 事务子流程中不能添加事件子流程;
- Camunda中的分布式事务一致性推荐用事务子流程 完成,业务最终一致性;
补偿事件 Compensation Event
1、按照补偿事件的定义,补偿事件只会在他标识的task成功执行完毕之后才有可能被触发;
2、如果他标识的task出现异常,会触发边界异常中断事件,这个补偿事件不会触发(Task出现异常(技术异常),Java事务自动回滚);
3、补偿开启事件只能用于嵌套的事件子流程;
事务子流程
撤销事件(Cacel Event)表示这个业务事务失败;
撤销事件只会出现在事务子流程中;
撤销事件有两个形态:
1、当它作为业务事务子流程的终态的时候,表明这个子流程是失败的,需要回滚,继而触发流程中各个任务所定义的补偿处理
2、当它作为业务事务子流程的边界事件的时候,标明这个子流程被回滚了,继而触发外部流程的回滚处理流程,和错误事件一样,撤销事件是中断的,即它会中断外部流程的正常执行路径。
注意:
边界中断取消事件触发时,事务子流程已经被回滚了(事务子流程中的所有补偿事件已经触发执行完成)。边界中断取消事件触发只是为了告诉外部任务,事务子流程已经回滚,如果外部任务需要回滚其他操作时,需要做其他业务操作。
事务子流程中如果有取消事件,必须要有边界取消中断事件
- 事务子流程中有取消事件,事务边界必须要有边界取消中断事件,否则执行时找不到边界中断事件报错
- 错误边界事件必须要有Code,否则错误边界事件不起作用,有异常捕获不到;
- 事务子流程中如果执行了取消事件,整个事务会自动执行对应任务(执行成功过的任务)的补偿事件
执行出异常的Groovy脚本
println "更新Redis过程中异常"
a=0
b=10/a
事务子流程外部可获取取消事件,外部任务回滚
有时事务子流程数据回滚后,外部已经提交了一些ACID任务时,也需要回滚。
可通过事务子流程边界中断取消事件,添加后续任务,回滚外部任务。
如下所示,外部任务回滚后,流程再次流到User Task 保存点(分布式任务回滚到原先保存点),此时流程不会结束,重新修改房源信息再次同步数据(有可能一直死循环回滚)。
事务子流程边界错误捕获事件,补偿事件不会触发
事务子流程中如果有未知的异常出现,而取消事件未触发;事务子流程边界错误中断事件可捕获到这些异常信息,但是此时不会触发补偿事件,也就是不会触发回滚。需要捕获到事务边界中断错误事件后,做一些业务回滚处理。
如下所示,在取消事件 中添加监听器,执行groovy脚本异常:
补偿任务边界不能添加中间事件
补偿任务边界上不能添加错误捕获事件,如果执行回滚时,也可能出现异常,此时错误时不能捕获到的,这个异常只能Camunda 引擎抛出,流程不能继续执行。
事务子流程中补偿事件子流程不会触发
**事务子流程中不需要补偿事件子流程,只要范围内出现取消事件
,对应所有Task补偿触发
Camunda 如何保证分布式事务一致性
Camunda 并不能操作多个ACID事务回滚,可通过事务子流程 取消事件+补偿事件,完成最终业务事务一致性。
在需要事务的每个Task任务上都需要添加补偿事件
Camunda 分布式事务一致性2种实现
- 事务子流程
- 补偿事件子流程(错误事件+补偿事件)
错误事件+补偿事件 事件子流程事务一致性?
事件子流程中“错误事件+补偿事件”是否可以完成事务一致性,如果可以为什么还需要有个事务子流程?
- 补偿事件子流程同样可以完成事务最终一致性,需要额外判断,实现麻烦;
- 事务子流程可简化事件子流程 完成事务一致性,更方便,推荐使用;
下面使用 补偿事件子流程 “错误事件+补偿事件”完成事务一致性案例:
错误事件+补偿事件 是否可完成事务一致性?
从下面案例可知,子流程出现异常后触发边界异常中断事件,后面补偿事件子流程 并没有执行。
补偿事件是在任务成功执行完成之后,有可能会触发。这里子流程任务失败了,所以子流程中的补偿事件子流程不会触发。所以以下案例并不能完成事务一致性。
错误事件+补偿事件如何处理可完成事务一致性?
上面案例子流程异常报错,触发边界错误事件,并没有触发补偿事件子流程。如果把子流程的异常内部吃了,不报出来,流程变量记录错误。子流程结束后,通过网关判断是否可完成事务一致性?
修改后的流程如下:
从下图可知这种补偿事件子流程也可以完成事务一致性操作,只是比事务子流程相对麻烦一些,对于业务事务比较强时,推荐通过事务子流程完成事务一致性。
Script Task 抓取错误异常信息记录流程变量
def id=execution.getProcessInstanceId()
// 是否出现异常信息
def hasError=false
if(execution.hasVariable("vrMsg")){
def errorMsg = execution.getVariable("vrMsg");
hasError=true;
println "流程实例:"+id+",出现异常:"+errorMsg
}
//异常标识设置到变量
execution.setVariable("hasError",hasError)
参考资料
http://www.jiagouc.com/camunda-error-handling-compensation-mechanism-and-distributed-transaction-support/