flowable 上一節(jié)點(diǎn)任務(wù)撤回-(2)會(huì)簽任務(wù)(已完成)

場(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.2

git地址:https://github.com/oldguys/flowable-modeler-demo/tree/branch_with_flowable_examples

所有章節(jié):

  1. flowable 上一節(jié)點(diǎn)任務(wù)撤回-(1)普通節(jié)點(diǎn)撤回
  2. flowable 上一節(jié)點(diǎn)任務(wù)撤回-(2)會(huì)簽任務(wù)(已完成)
  3. flowable 上一節(jié)點(diǎn)任務(wù)撤回-(3)會(huì)簽任務(wù)(正在執(zhí)行中)
  4. flowable 上一節(jié)點(diǎn)任務(wù)撤回-(4)多重網(wǎng)關(guān)
  5. flowable 上一節(jié)點(diǎn)任務(wù)撤回-(5)嵌入式子流程
  6. flowable 上一節(jié)點(diǎn)任務(wù)撤回-(6)調(diào)用式子流程

前置知識(shí):

  1. 會(huì)簽分為 并行 串行 兩種。
    并行會(huì)簽:會(huì)同時(shí)創(chuàng)建所有的任務(wù),依賴于變量進(jìn)行操作。如圖所示
并行會(huì)簽-正在執(zhí)行任務(wù)列表
并行會(huì)簽 -execution
并行會(huì)簽-變量

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

串行會(huì)簽-正在執(zhí)行任務(wù)
串行會(huì)簽-execution
串行會(huì)簽-變量
根據(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ù)完成之后

所有會(huì)簽任務(wù)完成之后-任務(wù)列表
所有會(huì)簽任務(wù)完成之后-execution
所有會(huì)簽任務(wù)完成之后-ACT_RU_VARIABLE

結(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ù)
普通節(jié)點(diǎn)回退到會(huì)簽節(jié)點(diǎn)

前置知識(shí)參考 第一章:

d-1 回退到 并行 c-1
步驟:

  1. 判斷 d-1 是否已經(jīng)完成,如果完成,則無(wú)法進(jìn)行回退。如果未完成,則到下一步驟

  2. 構(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)該回退。)

  3. 配置 剛剛構(gòu)建的 并行 c-1 的 父級(jí) Execution的變量:
    nrOfActiveInstances = 1
    nrOfCompletedInstances = 會(huì)簽總?cè)藬?shù)-1
    nrOfInstances = 會(huì)簽總?cè)藬?shù)
    execution.multiInstanceRoot = true

  4. 配置任務(wù)變量
    loopCounter = 會(huì)簽總?cè)藬?shù)最后一個(gè)集合下標(biāo)( 即:List.size()-1 )
    execution.active = true

  5. 如果是并行會(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ǔ)充。

  6. 構(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);

  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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容