終止流程代碼
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
