場(chǎng)景:本章主要描述 已完成會(huì)簽任務(wù) 如何進(jìn)行回退操作。
會(huì)簽任務(wù)進(jìn)行回退操作上一章:flowable 上一節(jié)點(diǎn)任務(wù)撤回-(1)普通節(jié)點(diǎn)撤回
下一章:[flowable 上一節(jié)點(diǎn)任務(wù)撤回-(3)會(huì)簽任務(wù)(正在執(zhí)行中)](http://www.itdecent.cn/p/6daf767b1084)ree/branch_with_flowable_examples]環(huán)境:
springboot:2.2.0.RELEASE
flowable:6.4.2git地址:https://github.com/oldguys/flowable-modeler-demo/tree/branch_with_flowable_examples
所有章節(jié):
- flowable 上一節(jié)點(diǎn)任務(wù)撤回-(1)普通節(jié)點(diǎn)撤回
- flowable 上一節(jié)點(diǎn)任務(wù)撤回-(2)會(huì)簽任務(wù)(已完成)
- flowable 上一節(jié)點(diǎn)任務(wù)撤回-(3)會(huì)簽任務(wù)(正在執(zhí)行中)
- flowable 上一節(jié)點(diǎn)任務(wù)撤回-(4)多重網(wǎng)關(guān)
- flowable 上一節(jié)點(diǎn)任務(wù)撤回-(5)嵌入式子流程
- flowable 上一節(jié)點(diǎn)任務(wù)撤回-(6)調(diào)用式子流程
前置知識(shí):
- 會(huì)簽分為 并行 串行 兩種。
并行會(huì)簽:會(huì)同時(shí)創(chuàng)建所有的任務(wù),依賴于變量進(jìn)行操作。如圖所示



串行會(huì)簽:按照變量順序逐次創(chuàng)建任務(wù),依賴于變量進(jìn)行操作。如圖所示



根據(jù)上面的圖可以分析出 關(guān)系:
execution 層次結(jié)構(gòu):
execution[流程實(shí)例] < Execution[會(huì)簽頂級(jí)實(shí)例] < Execution[實(shí)際會(huì)簽任務(wù)]
并行
1:1:3(設(shè)置變量數(shù)決定)
串行
1:1:1
其中可以看到 flowable 本身的變量
父級(jí)流程 execution變量:
nrOfActiveInstances:未完成任務(wù)個(gè)數(shù)
nrOfCompletedInstances:已完成任務(wù)個(gè)數(shù)
nrOfInstances:總?cè)蝿?wù)個(gè)數(shù)任務(wù)變量 execution
loopCounter:任務(wù)計(jì)數(shù)器
上面是執(zhí)行前的情況,當(dāng)所有會(huì)簽任務(wù)完成之后



結(jié)論1: 從上面圖片分析出,當(dāng)會(huì)簽任務(wù)走完,原本的變量會(huì)被清理掉。所以要 從 普通節(jié)點(diǎn) 退回到 會(huì)簽節(jié)點(diǎn),就必須模擬出這些變量。
結(jié)論2: 由于Execution也消失了,所以需要模擬出 2個(gè)層級(jí)的 execution。并且歷史execution變量將不可用
CompletedMultiInstanceTaskAndNextDefaultTaskRollbackOperateStrategy: 回退已完成會(huì)簽任務(wù)

前置知識(shí)參考 第一章:
d-1 回退到 并行 c-1
步驟:
判斷 d-1 是否已經(jīng)完成,如果完成,則無(wú)法進(jìn)行回退。如果未完成,則到下一步驟
構(gòu)建 并行 c-1 的 父級(jí) Execution,并構(gòu)建并構(gòu)建 任務(wù) execution(簡(jiǎn)稱:c-1任務(wù)),此時(shí)需要根據(jù)并行 , 串行 對(duì)變量進(jìn)行修改。(PS:串行的時(shí)候 還需要判斷 回退歷史任務(wù)的執(zhí)行人是否為 啟動(dòng)會(huì)簽任務(wù)時(shí)候入?yún)?集合 的最后一個(gè)參數(shù),如果不是的話,則不應(yīng)該回退。)
配置 剛剛構(gòu)建的 并行 c-1 的 父級(jí) Execution的變量:
nrOfActiveInstances = 1
nrOfCompletedInstances = 會(huì)簽總?cè)藬?shù)-1
nrOfInstances = 會(huì)簽總?cè)藬?shù)
execution.multiInstanceRoot = true配置任務(wù)變量
loopCounter = 會(huì)簽總?cè)藬?shù)最后一個(gè)集合下標(biāo)( 即:List.size()-1 )
execution.active = true如果是并行會(huì)簽,則需要補(bǔ)全 其他已完成任務(wù)的 execution,即創(chuàng)建 N-1 個(gè) 與 c-1 任務(wù) 同級(jí)的 exection ,但是 active = false,不生成任務(wù)。(不生成完成會(huì)簽任務(wù)execution會(huì)導(dǎo)致計(jì)數(shù)器無(wú)法執(zhí)行計(jì)滿,會(huì)導(dǎo)致無(wú)法到下一流程節(jié)點(diǎn))。 串行會(huì)簽由于使用的是同一個(gè) execution,所以不需要補(bǔ)充。
構(gòu)建任務(wù)的時(shí)候使用語(yǔ)句與構(gòu)建普通任務(wù)的語(yǔ)句不一樣:(使用同一個(gè)會(huì)出現(xiàn)直接構(gòu)建整個(gè)節(jié)點(diǎn))
CommandContextUtil.getAgenda(commandContext) .planContinueMultiInstanceOperation(newExecution, parentExecution, assignees.size() - 1);
- 之后的步驟與之前的操作一樣,刪除當(dāng)前執(zhí)行任務(wù),清除回退的歷史任務(wù),清除痕跡及關(guān)聯(lián),此處就不過(guò)多贅述。 可以參考第一章:
基于模板方法模式,構(gòu)建編寫(xiě)通用 RollbackOperateStrategy.process() 操作
@Override
public void process(CommandContext commandContext, String assignee, Map<String, Object> variables) {
this.commandContext = commandContext;
this.assignee = assignee;
this.variables = variables;
log.info("處理 existNextFinishedTask");
existNextFinishedTask();
log.info("配置任務(wù)執(zhí)行人 setAssignee");
setAssignee();
log.info("處理 createExecution");
createExecution();
log.info("處理 deleteRuntimeTasks");
deleteRuntimeTasks();
log.info("處理 deleteHisActInstance");
deleteHisActInstance();
}
創(chuàng)建 父級(jí) 會(huì)簽 execution
@Override
public void createExecution() {
if (paramsTemplate.getCurrentTaskElement().getBehavior() instanceof SequentialMultiInstanceBehavior) {
isSequence = true;
}
// 獲取 execution
ExecutionEntity executionEntity = getExecutionEntity();
VariableInstanceEntity obj = CommandContextUtil.getVariableService(commandContext)
.findVariableInstanceByExecutionAndName(executionEntity.getProcessInstanceId(), assigneeListExpr);
if (obj == null || !(obj.getValue() instanceof Collection)) {
throw new FlowableRuntimeException("沒(méi)有可用會(huì)簽參數(shù):" + assigneeListExpr);
}
// 會(huì)簽執(zhí)行人變量
Collection assignees = (Collection) obj.getValue();
List<HistoricVariableInstance> historicVariableInstances = CommandContextUtil.getHistoricVariableService()
.findHistoricVariableInstancesByQueryCriteria(
new HistoricVariableInstanceQueryImpl()
.executionId(paramsTemplate.getHisTask().getExecutionId())
);
if (historicVariableInstances.isEmpty()) {
throw new FlowableRuntimeException("沒(méi)有可用會(huì)簽任務(wù)參數(shù)");
}
// 歷史變量
Map<String, Object> hisVarMap = historicVariableInstances.stream().collect(Collectors.toMap(HistoricVariableInstance::getVariableName, item -> item.getValue()));
if (hisVarMap.containsKey(assigneeExpr) && hisVarMap.containsKey(RollbackConstants.MultiInstanceConstants.LOOP_COUNTER)) {
log.info("變量有效");
} else {
throw new FlowableRuntimeException("缺少會(huì)簽任務(wù)變量");
}
/**
* 串行 最終的 loopCounter assignee 都會(huì)是最后一個(gè)人
*/
if (isSequence) {
List<String> assigneeList = (List<String>) runtimeService.getVariableLocal(paramsTemplate.getHisTask().getProcessInstanceId(), assigneeListExpr);
if (!assigneeList.get(assigneeList.size() - 1).equals(paramsTemplate.getHisTask().getAssignee())) {
String msg = "不是串行最后一個(gè)節(jié)點(diǎn),無(wú)法進(jìn)行回退 ";
throw new FlowableRuntimeException(msg);
}
// 替換任務(wù)執(zhí)行變量
assigneeList.set(assigneeList.size() - 1, assignee);
runtimeService.setVariableLocal(paramsTemplate.getHisTask().getProcessInstanceId(), assigneeListExpr, assigneeList);
}
// 流程執(zhí)行變量
Integer loopCounter = (Integer) hisVarMap.get(RollbackConstants.MultiInstanceConstants.LOOP_COUNTER);
// 會(huì)簽主任務(wù)
ExecutionEntity parentExecution = CommandContextUtil.getExecutionEntityManager(commandContext)
.createChildExecution(executionEntity.getParent());
parentExecution.setCurrentFlowElement(paramsTemplate.getCurrentTaskElement());
parentExecution.setActive(false);
// 配置 會(huì)簽 root execution
parentExecution.setMultiInstanceRoot(true);
// 配置主 execution 變量
Map<String, Object> parentVarMap = new HashMap<>();
parentVarMap.put(RollbackConstants.MultiInstanceConstants.NR_OF_ACTIVE_INSTANCES, 1);
parentVarMap.put(RollbackConstants.MultiInstanceConstants.NR_OF_COMPLETE_INSTANCES, assignees.size() - 1);
parentVarMap.put(RollbackConstants.MultiInstanceConstants.NR_OF_INSTANCE, assignees.size());
parentExecution.setVariablesLocal(parentVarMap);
if (isSequence) {
log.info("創(chuàng)建 串行 會(huì)簽任務(wù)");
createSequenceMultiInstance(parentExecution, assignees);
} else {
log.info("創(chuàng)建 并行 會(huì)簽任務(wù)");
createParallelMultiInstance(parentExecution, assignees, loopCounter);
}
removeHisTask(paramsTemplate.getHisTask());
}
創(chuàng)建 串行會(huì)簽任務(wù):createSequenceMultiInstance
/**
* 創(chuàng)建并行會(huì)簽任務(wù)
*
* @param parentExecution
* @param loopCounter
*/
private void createParallelMultiInstance(ExecutionEntity parentExecution, Collection assignees, Integer loopCounter) {
for (int i = 0; i < assignees.size(); i++) {
if (i != loopCounter) {
Map<String, Object> varMap = new HashMap<>();
varMap.put(RollbackConstants.MultiInstanceConstants.LOOP_COUNTER, i);
varMap.put(assigneeExpr, "已完成任務(wù)");
// // 創(chuàng)建 新執(zhí)行任務(wù)
ExecutionEntity newExecution = newExecution = CommandContextUtil.getExecutionEntityManager(commandContext)
.createChildExecution(parentExecution);
newExecution.setCurrentFlowElement(paramsTemplate.getCurrentTaskElement());
newExecution.setActive(false);
newExecution.setVariablesLocal(varMap);
//
// CommandContextUtil.getExecutionEntityManager(commandContext)
// .update(newExecution);
} else {
ExecutionEntity newExecution = CommandContextUtil.getExecutionEntityManager(commandContext)
.createChildExecution(parentExecution);
newExecution.setCurrentFlowElement(paramsTemplate.getCurrentTaskElement());
Map<String, Object> varMap = new HashMap<>();
varMap.put(assigneeExpr, assignee);
varMap.put(RollbackConstants.MultiInstanceConstants.LOOP_COUNTER, i);
newExecution.setVariablesLocal(varMap);
newExecution.setActive(true);
CommandContextUtil.getAgenda(commandContext).planContinueMultiInstanceOperation(newExecution, parentExecution, loopCounter);
}
}
}
}
創(chuàng)建 并行會(huì)簽任務(wù):createSequenceMultiInstance
private void createSequenceMultiInstance(ExecutionEntity parentExecution, Collection assignees) {
ExecutionEntity newExecution = CommandContextUtil.getExecutionEntityManager(commandContext)
.createChildExecution(parentExecution);
Map<String, Object> varMap = new HashMap<>();
varMap.put(assigneeExpr, assignee);
varMap.put(RollbackConstants.MultiInstanceConstants.LOOP_COUNTER, assignees.size() - 1);
newExecution.setCurrentFlowElement(paramsTemplate.getCurrentTaskElement());
newExecution.setVariablesLocal(varMap);
newExecution.setActive(true);
CommandContextUtil.getAgenda(commandContext)
.planContinueMultiInstanceOperation(newExecution, parentExecution, assignees.size() - 1);
}
以上 完成對(duì) 上一節(jié)點(diǎn)任務(wù)撤回 架構(gòu)設(shè)計(jì) 及 第 2 種情況 解決方案講述。
git地址:https://github.com/oldguys/flowable-modeler-demo/tree/branch_with_flowable_examples
