關於工作流:flowable中終止流程二


終止流程代碼

public void stopProcessInstanceById(String processInstanceId) {
    ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
 if (processInstance != null) {
        //1、獲取終止節點
 List<EndEvent> endNodes =findEndFlowElement(processInstance.getProcessDefinitionId());
 String endId = endNodes.get(0).getId();
 //2、執行終止
 List<Execution> executions = runtimeService.createExecutionQuery().parentId(processInstanceId).list();
 List<String> executionIds = new ArrayList<>();
 executions.forEach(execution -> executionIds.add(execution.getId()));
 runtimeService.createChangeActivityStateBuilder().moveExecutionsToSingleActivityId(executionIds, endId).changeState();
 log.info("終止processInstanceId:{}勝利",processInstanceId);
 }else {
       log.info("不存在運行的流程實例processInstanceId:{},請確認!",processInstanceId);
 }
}
public List findEndFlowElement(String processDefId) {
    Process mainProcess = repositoryService.getBpmnModel(processDefId).getMainProcess();
 Collection<FlowElement> list = mainProcess.getFlowElements();
 if (CollectionUtils.isEmpty(list)) {
        return Collections.EMPTY_LIST;
 }
    return list.stream().filter(f -> f instanceof EndEvent).collect(Collectors.toList());
}


runtimeService.createChangeActivityStateBuilder().moveExecutionsToSingleActivityId(executionIds, endId)
並沒有changeState,正確的應用姿態是

runtimeService.createChangeActivityStateBuilder().moveExecutionsToSingleActivityId(executionIds, endId).changeState();
沒有調用changeState辦法是不會失效的
坑2:在serviceTask中調用

flowableInstanceService.stopProcessInstanceById(delegateExecution.getProcessInstanceId());
若該serviceTask中拋出Exception,會產生詭異的操作:
流程並沒有順利終止掉。
為什么?flowable中應用的默認的流傳行為為Required(沒有事務則新建一個事務),而serviceTask是在事務中執行的(能夠理解flowable源碼之命令模式,若servicetask中拋出異樣,則相應的數據庫操作會被全副回滾掉),完結流程這個辦法會沿用這個事務,當該servicetask拋出謬誤后,會回滾掉籌備提交的sqlsession
解決思路:
1.應用多線程,異步執行終止流程操作

executorService.submit(() -> flowableInstanceService.stopProcessInstanceById(delegateExecution.getProcessInstanceId()));
引發問題:史詩級巨坑,排查了很久,偶然執行勝利,偶然執行失敗,不拋錯,也沒有異樣。
排查問題思路:flowableInstanceService.stopProcessInstanceById真的執行結束了嗎?為什么數據庫的狀態沒有扭轉,這里是其余線程,沒有再開啟事務了,不存在之前的事務流傳行為的問題。
通過打印日志的形式,我哭了

executorService.execute(() -> {
    log.info("終止processInstanceId:{}工作開始",delegateExecution.getProcessInstanceId());
 flowableInstanceService.stopProcessInstanceById(delegateExecution.getProcessInstanceId());
 log.info("終止processInstanceId:{}工作完結",delegateExecution.getProcessInstanceId());
});
工作完結的日志居然沒有打印,我狐疑可能拋出了異樣,為了驗證問題所在,線程減少日志打印解決

@Bean
public ExecutorService executorService() {
    return Executors.newSingleThreadExecutor(new HandleThreadFactory());
}
class HandleThreadFactory implements ThreadFactory {
    @Override
 public Thread newThread(Runnable r) {
        System.out.println("create thread t");
 Thread t = new Thread(r);
 System.out.println("set uncaughtException for t");
 t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
 public void uncaughtException(Thread t, Throwable e) {
                log.error("caught exception:" + e);
 }
        });
 return t;
 }
}
無果??異樣沒有被捕捉到,原來,應用executorService.execute()才會被捕捉到,於是更換成executorService.execute()辦法來運行

原來,這個中央拋出了異樣。思考了很久,應該是並發導致的問題
serviceTask的線程為A線程,完結流程的線程為B線程
A線程當前任務節點為servicetask1,
B線程讀取當前任務節點為servicetask1,並希圖挪動到end節點
A線程拋錯或者serviceTask1執行結束,工作節點多會變動為定時器(重試機制)或者serviceTask2(失常流轉)
B線程執行操作,挪動到end節點,偽代碼sql為update to end where node is serviceTask1,然而留神留神,A線程曾經commit了具體的最新的以后節點的值,A線程拿到的還是老數據,故操作失敗,updateCount為0,拋出異


拓展:flowable為了並發性能,應用的是偽並發,即樂觀鎖機制,樂觀的認為所有的數據都是沒有競爭的,不減輕鎖。失敗就會拋出此異樣
最終解決辦法:
不拋異樣,間接同步終止流程

 

flowableInstanceService.stopProcessInstanceById(delegateExecution.getProcessInstanceId());

  轉載   https://lequ7.com/guan-yu-gong-zuo-liu-flowable-zhong-zhong-zhi-liu-cheng-er.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM