Java tutorial
/* * Copyright (C) 2017 Baifendian Corporation * * Licensed 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 com.baifendian.swordfish.execserver.runner.flow; import com.baifendian.swordfish.dao.DaoFactory; import com.baifendian.swordfish.dao.FlowDao; import com.baifendian.swordfish.dao.model.ExecutionFlow; import com.baifendian.swordfish.execserver.utils.Constants; import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import org.apache.commons.configuration.Configuration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Flow ? <p> */ public class FlowRunnerManager { private final Logger logger = LoggerFactory.getLogger(getClass()); /** * {@link FlowDao} */ private final FlowDao flowDao; /** * flow ? */ private final ExecutorService flowExecutorService; /** * ? */ private final ExecutorService nodeExecutorService; /** * ? flows, key => flow id, value => flow runner */ private final Map<Integer, FlowRunner> runningFlows = new ConcurrentHashMap<>(); public FlowRunnerManager(Configuration conf) { this.flowDao = DaoFactory.getDaoInstance(FlowDao.class); int flowThreads = conf.getInt(Constants.EXECUTOR_FLOWRUNNER_THREADS, Constants.defaultFlowRunnerThreadNum); ThreadFactory flowThreadFactory = new ThreadFactoryBuilder().setNameFormat("Exec-Worker-FlowRunner") .build(); flowExecutorService = Executors.newFixedThreadPool(flowThreads, flowThreadFactory); int nodeThreads = conf.getInt(Constants.EXECUTOR_NODERUNNER_THREADS, Constants.defaultNodeRunnerThreadNum); ThreadFactory nodeThreadFactory = new ThreadFactoryBuilder().setNameFormat("Exec-Worker-NodeRunner") .build(); nodeExecutorService = Executors.newFixedThreadPool(nodeThreads, nodeThreadFactory); // ?? runningFlows ?? Thread cleanThread = new Thread(() -> { while (true) { try { cleanFinishedFlows(); } catch (Exception e) { logger.error("clean thread error ", e); } finally { try { Thread.sleep(Constants.defaultCleanFinishFlowInterval); } catch (InterruptedException e) { } } } }); cleanThread.setDaemon(true); cleanThread.setName("finishedFlowClean"); cleanThread.start(); } /** * ?? workflow <p> */ public void submitFlow(ExecutionFlow executionFlow) { if (runningFlows.containsKey(executionFlow.getId())) { logger.info("flow is in running: {}", executionFlow.getId()); return; } int maxTryTimes = executionFlow.getMaxTryTimes() != null ? executionFlow.getMaxTryTimes() : Constants.defaultMaxTryTimes; int timeout = executionFlow.getTimeout() != null ? executionFlow.getTimeout() : Constants.defaultMaxTimeout; // flow runner ? FlowRunnerContext context = new FlowRunnerContext(); context.setExecutionFlow(executionFlow); context.setNodeExecutorService(nodeExecutorService); context.setMaxTryTimes(maxTryTimes); context.setTimeout(timeout); context.setFailurePolicyType(executionFlow.getFailurePolicy()); FlowRunner flowRunner = new FlowRunner(context); // ?, ?? if (!runningFlows.containsKey(executionFlow.getId())) { runningFlows.putIfAbsent(executionFlow.getId(), flowRunner); logger.info( "submit flow, exec id: {}, project name: {}, workflow name: {}, max try times: {}, timeout: {}", executionFlow.getId(), executionFlow.getProjectName(), executionFlow.getWorkflowName(), maxTryTimes, timeout); flowExecutorService.submit(flowRunner); } } /** * ?? flows */ private void cleanFinishedFlows() { List<Integer> finishFlows = new ArrayList<>(); synchronized (this) { for (Map.Entry<Integer, FlowRunner> entry : runningFlows.entrySet()) { ExecutionFlow executionFlow = flowDao.queryExecutionFlow(entry.getKey()); if (executionFlow != null && executionFlow.getStatus().typeIsFinished()) { finishFlows.add(entry.getKey()); } } } for (Integer id : finishFlows) { runningFlows.remove(id); } } /** * ?? <p> */ public void destroy() { // flow executor , ?? shutdownExecutorService(flowExecutorService, false); // node executor , ?? shutdownExecutorService(nodeExecutorService, false); for (FlowRunner flowRunner : runningFlows.values()) { flowRunner.shutdown(); // ? flowRunner.clean(false); // kill ? flowRunner.updateExecutionFlowToKillStatus(false); } // flow executor , ? shutdownExecutorService(flowExecutorService, true); // flow executor , ? shutdownExecutorService(nodeExecutorService, true); try { Thread.sleep(5000); } catch (InterruptedException e) { logger.error("Catch an interrupt exception", e); } } /** * executor service */ private void shutdownExecutorService(ExecutorService executorService, boolean shutdownNow) { if (!executorService.isShutdown()) { try { if (!shutdownNow) { executorService.shutdown(); } else { executorService.shutdownNow(); } executorService.awaitTermination(3, TimeUnit.SECONDS); } catch (Exception e) { logger.error(e.getMessage(), e); } } } /** * ? flow */ public void cancelFlow(ExecutionFlow executionFlow) { int execId = executionFlow.getId(); FlowRunner flowRunner = runningFlows.get(execId); if (flowRunner == null) { logger.error("Execution id {} is not running", execId); return; } flowRunner.clean(true); runningFlows.remove(execId); } }