Browse Source
* threadpool optimization * threadpool params * rebase dev * ut check fix * add return * rebase dev * event loop Co-authored-by: caishunfeng <534328519@qq.com>3.0.0/version-upgrade
wind
3 years ago
committed by
GitHub
11 changed files with 414 additions and 344 deletions
@ -0,0 +1,181 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.server.master.runner; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.common.enums.ExecutionStatus; |
||||||
|
import org.apache.dolphinscheduler.common.enums.Flag; |
||||||
|
import org.apache.dolphinscheduler.common.enums.StateEvent; |
||||||
|
import org.apache.dolphinscheduler.common.enums.StateEventType; |
||||||
|
import org.apache.dolphinscheduler.common.utils.NetUtils; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.ProcessInstance; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.TaskInstance; |
||||||
|
import org.apache.dolphinscheduler.remote.command.StateEventChangeCommand; |
||||||
|
import org.apache.dolphinscheduler.remote.processor.StateEventCallbackService; |
||||||
|
import org.apache.dolphinscheduler.server.master.cache.ProcessInstanceExecCacheManager; |
||||||
|
import org.apache.dolphinscheduler.server.master.config.MasterConfig; |
||||||
|
import org.apache.dolphinscheduler.service.process.ProcessService; |
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils; |
||||||
|
|
||||||
|
import java.util.Map; |
||||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||||
|
|
||||||
|
import javax.annotation.PostConstruct; |
||||||
|
|
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; |
||||||
|
import org.springframework.stereotype.Component; |
||||||
|
import org.springframework.util.concurrent.ListenableFuture; |
||||||
|
import org.springframework.util.concurrent.ListenableFutureCallback; |
||||||
|
|
||||||
|
@Component |
||||||
|
public class WorkflowExecuteThreadPool extends ThreadPoolTaskExecutor { |
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(WorkflowExecuteThreadPool.class); |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private MasterConfig masterConfig; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private ProcessService processService; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private ProcessInstanceExecCacheManager processInstanceExecCacheManager; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private StateEventCallbackService stateEventCallbackService; |
||||||
|
|
||||||
|
/** |
||||||
|
* multi-thread filter, avoid handling workflow at the same time |
||||||
|
*/ |
||||||
|
private ConcurrentHashMap<String, WorkflowExecuteThread> multiThreadFilterMap = new ConcurrentHashMap(); |
||||||
|
|
||||||
|
@PostConstruct |
||||||
|
private void init() { |
||||||
|
this.setDaemon(true); |
||||||
|
this.setThreadNamePrefix("Workflow-Execute-Thread-"); |
||||||
|
this.setMaxPoolSize(masterConfig.getExecThreads()); |
||||||
|
this.setCorePoolSize(masterConfig.getExecThreads()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* submit state event |
||||||
|
*/ |
||||||
|
public void submitStateEvent(StateEvent stateEvent) { |
||||||
|
WorkflowExecuteThread workflowExecuteThread = processInstanceExecCacheManager.getByProcessInstanceId(stateEvent.getProcessInstanceId()); |
||||||
|
if (workflowExecuteThread == null) { |
||||||
|
logger.error("workflowExecuteThread is null, processInstanceId:{}", stateEvent.getProcessInstanceId()); |
||||||
|
return; |
||||||
|
} |
||||||
|
workflowExecuteThread.addStateEvent(stateEvent); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* start workflow |
||||||
|
*/ |
||||||
|
public void startWorkflow(WorkflowExecuteThread workflowExecuteThread) { |
||||||
|
submit(workflowExecuteThread::startProcess); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* execute workflow |
||||||
|
*/ |
||||||
|
public void executeEvent(WorkflowExecuteThread workflowExecuteThread) { |
||||||
|
if (!workflowExecuteThread.isStart() || workflowExecuteThread.eventSize() == 0) { |
||||||
|
return; |
||||||
|
} |
||||||
|
if (multiThreadFilterMap.containsKey(workflowExecuteThread.getKey())) { |
||||||
|
return; |
||||||
|
} |
||||||
|
int processInstanceId = workflowExecuteThread.getProcessInstance().getId(); |
||||||
|
ListenableFuture future = this.submitListenable(() -> { |
||||||
|
workflowExecuteThread.handleEvents(); |
||||||
|
multiThreadFilterMap.put(workflowExecuteThread.getKey(), workflowExecuteThread); |
||||||
|
}); |
||||||
|
future.addCallback(new ListenableFutureCallback() { |
||||||
|
@Override |
||||||
|
public void onFailure(Throwable ex) { |
||||||
|
logger.error("handle events {} failed", processInstanceId, ex); |
||||||
|
multiThreadFilterMap.remove(workflowExecuteThread.getKey()); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onSuccess(Object result) { |
||||||
|
if (workflowExecuteThread.workFlowFinish()) { |
||||||
|
processInstanceExecCacheManager.removeByProcessInstanceId(processInstanceId); |
||||||
|
notifyProcessChanged(workflowExecuteThread.getProcessInstance()); |
||||||
|
logger.info("process instance {} finished.", processInstanceId); |
||||||
|
} |
||||||
|
multiThreadFilterMap.remove(workflowExecuteThread.getKey()); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* notify process change |
||||||
|
*/ |
||||||
|
private void notifyProcessChanged(ProcessInstance finishProcessInstance) { |
||||||
|
if (Flag.NO == finishProcessInstance.getIsSubProcess()) { |
||||||
|
return; |
||||||
|
} |
||||||
|
Map<ProcessInstance, TaskInstance> fatherMaps = processService.notifyProcessList(finishProcessInstance.getId()); |
||||||
|
for (ProcessInstance processInstance : fatherMaps.keySet()) { |
||||||
|
String address = NetUtils.getAddr(masterConfig.getListenPort()); |
||||||
|
if (processInstance.getHost().equalsIgnoreCase(address)) { |
||||||
|
this.notifyMyself(processInstance, fatherMaps.get(processInstance)); |
||||||
|
} else { |
||||||
|
this.notifyProcess(finishProcessInstance, processInstance, fatherMaps.get(processInstance)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* notify myself |
||||||
|
*/ |
||||||
|
private void notifyMyself(ProcessInstance processInstance, TaskInstance taskInstance) { |
||||||
|
logger.info("notify process {} task {} state change", processInstance.getId(), taskInstance.getId()); |
||||||
|
if (!processInstanceExecCacheManager.contains(processInstance.getId())) { |
||||||
|
return; |
||||||
|
} |
||||||
|
StateEvent stateEvent = new StateEvent(); |
||||||
|
stateEvent.setTaskInstanceId(taskInstance.getId()); |
||||||
|
stateEvent.setType(StateEventType.TASK_STATE_CHANGE); |
||||||
|
stateEvent.setProcessInstanceId(processInstance.getId()); |
||||||
|
stateEvent.setExecutionStatus(ExecutionStatus.RUNNING_EXECUTION); |
||||||
|
this.submitStateEvent(stateEvent); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* notify process's master |
||||||
|
*/ |
||||||
|
private void notifyProcess(ProcessInstance finishProcessInstance, ProcessInstance processInstance, TaskInstance taskInstance) { |
||||||
|
String host = processInstance.getHost(); |
||||||
|
if (StringUtils.isEmpty(host)) { |
||||||
|
logger.error("process {} host is empty, cannot notify task {} now", processInstance.getId(), taskInstance.getId()); |
||||||
|
return; |
||||||
|
} |
||||||
|
String address = host.split(":")[0]; |
||||||
|
int port = Integer.parseInt(host.split(":")[1]); |
||||||
|
StateEventChangeCommand stateEventChangeCommand = new StateEventChangeCommand( |
||||||
|
finishProcessInstance.getId(), 0, finishProcessInstance.getState(), processInstance.getId(), taskInstance.getId() |
||||||
|
); |
||||||
|
stateEventCallbackService.sendResult(address, port, stateEventChangeCommand.convert2Command()); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue