/* * 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.service.process; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.cronutils.model.Cron; import org.apache.commons.lang.ArrayUtils; import org.apache.dolphinscheduler.common.Constants; import org.apache.dolphinscheduler.common.enums.*; import org.apache.dolphinscheduler.common.model.DateInterval; import org.apache.dolphinscheduler.common.model.TaskNode; import org.apache.dolphinscheduler.common.process.Property; import org.apache.dolphinscheduler.common.task.subprocess.SubProcessParameters; import org.apache.dolphinscheduler.common.utils.*; import org.apache.dolphinscheduler.dao.entity.*; import org.apache.dolphinscheduler.dao.mapper.*; import org.apache.dolphinscheduler.remote.utils.Host; import org.apache.dolphinscheduler.service.log.LogClientService; import org.apache.dolphinscheduler.service.quartz.cron.CronUtils; import org.quartz.CronExpression; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import java.io.File; import java.util.*; import java.util.stream.Collectors; import static java.util.stream.Collectors.toSet; import static org.apache.dolphinscheduler.common.Constants.*; /** * process relative dao that some mappers in this. */ @Component public class ProcessService { private final Logger logger = LoggerFactory.getLogger(getClass()); private final int[] stateArray = new int[]{ExecutionStatus.SUBMITTED_SUCCESS.ordinal(), ExecutionStatus.RUNNING_EXEUTION.ordinal(), ExecutionStatus.READY_PAUSE.ordinal(), ExecutionStatus.READY_STOP.ordinal()}; @Autowired private UserMapper userMapper; @Autowired private ProcessDefinitionMapper processDefineMapper; @Autowired private ProcessInstanceMapper processInstanceMapper; @Autowired private DataSourceMapper dataSourceMapper; @Autowired private ProcessInstanceMapMapper processInstanceMapMapper; @Autowired private TaskInstanceMapper taskInstanceMapper; @Autowired private CommandMapper commandMapper; @Autowired private ScheduleMapper scheduleMapper; @Autowired private UdfFuncMapper udfFuncMapper; @Autowired private ResourceMapper resourceMapper; @Autowired private ErrorCommandMapper errorCommandMapper; @Autowired private TenantMapper tenantMapper; @Autowired private ProjectMapper projectMapper; /** * handle Command (construct ProcessInstance from Command) , wrapped in transaction * @param logger logger * @param host host * @param validThreadNum validThreadNum * @param command found command * @return process instance */ @Transactional(rollbackFor = Exception.class) public ProcessInstance handleCommand(Logger logger, String host, int validThreadNum, Command command) { ProcessInstance processInstance = constructProcessInstance(command, host); //cannot construct process instance, return null; if(processInstance == null){ logger.error("scan command, command parameter is error: {}", command); moveToErrorCommand(command, "process instance is null"); return null; } if(!checkThreadNum(command, validThreadNum)){ logger.info("there is not enough thread for this command: {}", command); return setWaitingThreadProcess(command, processInstance); } if (processInstance.getCommandType().equals(CommandType.RECOVER_TOLERANCE_FAULT_PROCESS)){ delCommandByid(command.getId()); return null; } processInstance.setCommandType(command.getCommandType()); processInstance.addHistoryCmd(command.getCommandType()); saveProcessInstance(processInstance); this.setSubProcessParam(processInstance); delCommandByid(command.getId()); return processInstance; } /** * save error command, and delete original command * @param command command * @param message message */ @Transactional(rollbackFor = Exception.class) public void moveToErrorCommand(Command command, String message) { ErrorCommand errorCommand = new ErrorCommand(command, message); this.errorCommandMapper.insert(errorCommand); delCommandByid(command.getId()); } /** * set process waiting thread * @param command command * @param processInstance processInstance * @return process instance */ private ProcessInstance setWaitingThreadProcess(Command command, ProcessInstance processInstance) { processInstance.setState(ExecutionStatus.WAITTING_THREAD); if(command.getCommandType() != CommandType.RECOVER_WAITTING_THREAD){ processInstance.addHistoryCmd(command.getCommandType()); } saveProcessInstance(processInstance); this.setSubProcessParam(processInstance); createRecoveryWaitingThreadCommand(command, processInstance); return null; } /** * check thread num * @param command command * @param validThreadNum validThreadNum * @return if thread is enough */ private boolean checkThreadNum(Command command, int validThreadNum) { int commandThreadCount = this.workProcessThreadNumCount(command.getProcessDefinitionId()); return validThreadNum >= commandThreadCount; } /** * insert one command * @param command command * @return create result */ public int createCommand(Command command) { int result = 0; if (command != null){ result = commandMapper.insert(command); } return result; } /** * find one command from queue list * @return command */ public Command findOneCommand(){ return commandMapper.getOneToRun(); } /** * check the input command exists in queue list * @param command command * @return create command result */ public Boolean verifyIsNeedCreateCommand(Command command){ Boolean isNeedCreate = true; Map cmdTypeMap = new HashMap(); cmdTypeMap.put(CommandType.REPEAT_RUNNING,1); cmdTypeMap.put(CommandType.RECOVER_SUSPENDED_PROCESS,1); cmdTypeMap.put(CommandType.START_FAILURE_TASK_PROCESS,1); CommandType commandType = command.getCommandType(); if(cmdTypeMap.containsKey(commandType)){ JSONObject cmdParamObj = (JSONObject) JSON.parse(command.getCommandParam()); JSONObject tempObj; int processInstanceId = cmdParamObj.getInteger(CMDPARAM_RECOVER_PROCESS_ID_STRING); List commands = commandMapper.selectList(null); // for all commands for (Command tmpCommand:commands){ if(cmdTypeMap.containsKey(tmpCommand.getCommandType())){ tempObj = (JSONObject) JSON.parse(tmpCommand.getCommandParam()); if(tempObj != null && processInstanceId == tempObj.getInteger(CMDPARAM_RECOVER_PROCESS_ID_STRING)){ isNeedCreate = false; break; } } } } return isNeedCreate; } /** * find process instance detail by id * @param processId processId * @return process instance */ public ProcessInstance findProcessInstanceDetailById(int processId){ return processInstanceMapper.queryDetailById(processId); } /** * get task node list by definitionId * @param defineId * @return */ public List getTaskNodeListByDefinitionId(Integer defineId){ ProcessDefinition processDefinition = processDefineMapper.selectById(defineId); if (processDefinition == null) { logger.info("process define not exists"); return null; } String processDefinitionJson = processDefinition.getProcessDefinitionJson(); ProcessData processData = JSONUtils.parseObject(processDefinitionJson, ProcessData.class); //process data check if (null == processData) { logger.error("process data is null"); return null; } return processData.getTasks(); } /** * find process instance by id * @param processId processId * @return process instance */ public ProcessInstance findProcessInstanceById(int processId){ return processInstanceMapper.selectById(processId); } /** * find process define by id. * @param processDefinitionId processDefinitionId * @return process definition */ public ProcessDefinition findProcessDefineById(int processDefinitionId) { return processDefineMapper.selectById(processDefinitionId); } /** * delete work process instance by id * @param processInstanceId processInstanceId * @return delete process instance result */ public int deleteWorkProcessInstanceById(int processInstanceId){ return processInstanceMapper.deleteById(processInstanceId); } /** * delete all sub process by parent instance id * @param processInstanceId processInstanceId * @return delete all sub process instance result */ public int deleteAllSubWorkProcessByParentId(int processInstanceId){ List subProcessIdList = processInstanceMapMapper.querySubIdListByParentId(processInstanceId); for(Integer subId : subProcessIdList){ deleteAllSubWorkProcessByParentId(subId); deleteWorkProcessMapByParentId(subId); removeTaskLogFile(subId); deleteWorkProcessInstanceById(subId); } return 1; } /** * remove task log file * @param processInstanceId processInstanceId */ public void removeTaskLogFile(Integer processInstanceId){ LogClientService logClient = new LogClientService(); List taskInstanceList = findValidTaskListByProcessId(processInstanceId); if (CollectionUtils.isEmpty(taskInstanceList)){ return; } for (TaskInstance taskInstance : taskInstanceList){ String taskLogPath = taskInstance.getLogPath(); if (StringUtils.isEmpty(taskInstance.getHost())){ continue; } String ip = Host.of(taskInstance.getHost()).getIp(); int port = Constants.RPC_PORT; // remove task log from loggerserver logClient.removeTaskLog(ip,port,taskLogPath); } } /** * calculate sub process number in the process define. * @param processDefinitionId processDefinitionId * @return process thread num count */ private Integer workProcessThreadNumCount(Integer processDefinitionId){ List ids = new ArrayList<>(); recurseFindSubProcessId(processDefinitionId, ids); return ids.size()+1; } /** * recursive query sub process definition id by parent id. * @param parentId parentId * @param ids ids */ public void recurseFindSubProcessId(int parentId, List ids){ ProcessDefinition processDefinition = processDefineMapper.selectById(parentId); String processDefinitionJson = processDefinition.getProcessDefinitionJson(); ProcessData processData = JSONUtils.parseObject(processDefinitionJson, ProcessData.class); List taskNodeList = processData.getTasks(); if (taskNodeList != null && taskNodeList.size() > 0){ for (TaskNode taskNode : taskNodeList){ String parameter = taskNode.getParams(); JSONObject parameterJson = JSONObject.parseObject(parameter); if (parameterJson.getInteger(CMDPARAM_SUB_PROCESS_DEFINE_ID) != null){ SubProcessParameters subProcessParam = JSON.parseObject(parameter, SubProcessParameters.class); ids.add(subProcessParam.getProcessDefinitionId()); recurseFindSubProcessId(subProcessParam.getProcessDefinitionId(),ids); } } } } /** * create recovery waiting thread command when thread pool is not enough for the process instance. * sub work process instance need not to create recovery command. * create recovery waiting thread command and delete origin command at the same time. * if the recovery command is exists, only update the field update_time * @param originCommand originCommand * @param processInstance processInstance */ public void createRecoveryWaitingThreadCommand(Command originCommand, ProcessInstance processInstance) { // sub process doesnot need to create wait command if(processInstance.getIsSubProcess() == Flag.YES){ if(originCommand != null){ commandMapper.deleteById(originCommand.getId()); } return; } Map cmdParam = new HashMap<>(); cmdParam.put(Constants.CMDPARAM_RECOVERY_WAITTING_THREAD, String.valueOf(processInstance.getId())); // process instance quit by "waiting thread" state if(originCommand == null){ Command command = new Command( CommandType.RECOVER_WAITTING_THREAD, processInstance.getTaskDependType(), processInstance.getFailureStrategy(), processInstance.getExecutorId(), processInstance.getProcessDefinitionId(), JSONUtils.toJson(cmdParam), processInstance.getWarningType(), processInstance.getWarningGroupId(), processInstance.getScheduleTime(), processInstance.getProcessInstancePriority() ); saveCommand(command); return ; } // update the command time if current command if recover from waiting if(originCommand.getCommandType() == CommandType.RECOVER_WAITTING_THREAD){ originCommand.setUpdateTime(new Date()); saveCommand(originCommand); }else{ // delete old command and create new waiting thread command commandMapper.deleteById(originCommand.getId()); originCommand.setId(0); originCommand.setCommandType(CommandType.RECOVER_WAITTING_THREAD); originCommand.setUpdateTime(new Date()); originCommand.setCommandParam(JSONUtils.toJson(cmdParam)); originCommand.setProcessInstancePriority(processInstance.getProcessInstancePriority()); saveCommand(originCommand); } } /** * get schedule time from command * @param command command * @param cmdParam cmdParam map * @return date */ private Date getScheduleTime(Command command, Map cmdParam){ Date scheduleTime = command.getScheduleTime(); if(scheduleTime == null){ if(cmdParam != null && cmdParam.containsKey(CMDPARAM_COMPLEMENT_DATA_START_DATE)){ scheduleTime = DateUtils.stringToDate(cmdParam.get(CMDPARAM_COMPLEMENT_DATA_START_DATE)); } } return scheduleTime; } /** * generate a new work process instance from command. * @param processDefinition processDefinition * @param command command * @param cmdParam cmdParam map * @return process instance */ private ProcessInstance generateNewProcessInstance(ProcessDefinition processDefinition, Command command, Map cmdParam){ ProcessInstance processInstance = new ProcessInstance(processDefinition); processInstance.setState(ExecutionStatus.RUNNING_EXEUTION); processInstance.setRecovery(Flag.NO); processInstance.setStartTime(new Date()); processInstance.setRunTimes(1); processInstance.setMaxTryTimes(0); processInstance.setProcessDefinitionId(command.getProcessDefinitionId()); processInstance.setCommandParam(command.getCommandParam()); processInstance.setCommandType(command.getCommandType()); processInstance.setIsSubProcess(Flag.NO); processInstance.setTaskDependType(command.getTaskDependType()); processInstance.setFailureStrategy(command.getFailureStrategy()); processInstance.setExecutorId(command.getExecutorId()); WarningType warningType = command.getWarningType() == null ? WarningType.NONE : command.getWarningType(); processInstance.setWarningType(warningType); Integer warningGroupId = command.getWarningGroupId() == null ? 0 : command.getWarningGroupId(); processInstance.setWarningGroupId(warningGroupId); // schedule time Date scheduleTime = getScheduleTime(command, cmdParam); if(scheduleTime != null){ processInstance.setScheduleTime(scheduleTime); } processInstance.setCommandStartTime(command.getStartTime()); processInstance.setLocations(processDefinition.getLocations()); processInstance.setConnects(processDefinition.getConnects()); // curing global params processInstance.setGlobalParams(ParameterUtils.curingGlobalParams( processDefinition.getGlobalParamMap(), processDefinition.getGlobalParamList(), getCommandTypeIfComplement(processInstance, command), processInstance.getScheduleTime())); //copy process define json to process instance processInstance.setProcessInstanceJson(processDefinition.getProcessDefinitionJson()); // set process instance priority processInstance.setProcessInstancePriority(command.getProcessInstancePriority()); String workerGroup = StringUtils.isBlank(command.getWorkerGroup()) ? Constants.DEFAULT_WORKER_GROUP : command.getWorkerGroup(); processInstance.setWorkerGroup(workerGroup); processInstance.setTimeout(processDefinition.getTimeout()); processInstance.setTenantId(processDefinition.getTenantId()); return processInstance; } /** * get process tenant * there is tenant id in definition, use the tenant of the definition. * if there is not tenant id in the definiton or the tenant not exist * use definition creator's tenant. * @param tenantId tenantId * @param userId userId * @return tenant */ public Tenant getTenantForProcess(int tenantId, int userId){ Tenant tenant = null; if(tenantId >= 0){ tenant = tenantMapper.queryById(tenantId); } if (userId == 0){ return null; } if(tenant == null){ User user = userMapper.selectById(userId); tenant = tenantMapper.queryById(user.getTenantId()); } return tenant; } /** * check command parameters is valid * @param command command * @param cmdParam cmdParam map * @return whether command param is valid */ private Boolean checkCmdParam(Command command, Map cmdParam){ if(command.getTaskDependType() == TaskDependType.TASK_ONLY || command.getTaskDependType()== TaskDependType.TASK_PRE){ if(cmdParam == null || !cmdParam.containsKey(Constants.CMDPARAM_START_NODE_NAMES) || cmdParam.get(Constants.CMDPARAM_START_NODE_NAMES).isEmpty()){ logger.error("command node depend type is {}, but start nodes is null ", command.getTaskDependType()); return false; } } return true; } /** * construct process instance according to one command. * @param command command * @param host host * @return process instance */ private ProcessInstance constructProcessInstance(Command command, String host){ ProcessInstance processInstance = null; CommandType commandType = command.getCommandType(); Map cmdParam = JSONUtils.toMap(command.getCommandParam()); ProcessDefinition processDefinition = null; if(command.getProcessDefinitionId() != 0){ processDefinition = processDefineMapper.selectById(command.getProcessDefinitionId()); if(processDefinition == null){ logger.error("cannot find the work process define! define id : {}", command.getProcessDefinitionId()); return null; } } if(cmdParam != null ){ Integer processInstanceId = 0; // recover from failure or pause tasks if(cmdParam.containsKey(Constants.CMDPARAM_RECOVER_PROCESS_ID_STRING)) { String processId = cmdParam.get(Constants.CMDPARAM_RECOVER_PROCESS_ID_STRING); processInstanceId = Integer.parseInt(processId); if (processInstanceId == 0) { logger.error("command parameter is error, [ ProcessInstanceId ] is 0"); return null; } }else if(cmdParam.containsKey(Constants.CMDPARAM_SUB_PROCESS)){ // sub process map String pId = cmdParam.get(Constants.CMDPARAM_SUB_PROCESS); processInstanceId = Integer.parseInt(pId); }else if(cmdParam.containsKey(Constants.CMDPARAM_RECOVERY_WAITTING_THREAD)){ // waiting thread command String pId = cmdParam.get(Constants.CMDPARAM_RECOVERY_WAITTING_THREAD); processInstanceId = Integer.parseInt(pId); } if(processInstanceId ==0){ processInstance = generateNewProcessInstance(processDefinition, command, cmdParam); }else{ processInstance = this.findProcessInstanceDetailById(processInstanceId); } processDefinition = processDefineMapper.selectById(processInstance.getProcessDefinitionId()); processInstance.setProcessDefinition(processDefinition); //reset command parameter if(processInstance.getCommandParam() != null){ Map processCmdParam = JSONUtils.toMap(processInstance.getCommandParam()); for(Map.Entry entry: processCmdParam.entrySet()) { if(!cmdParam.containsKey(entry.getKey())){ cmdParam.put(entry.getKey(), entry.getValue()); } } } // reset command parameter if sub process if(cmdParam.containsKey(Constants.CMDPARAM_SUB_PROCESS)){ processInstance.setCommandParam(command.getCommandParam()); } }else{ // generate one new process instance processInstance = generateNewProcessInstance(processDefinition, command, cmdParam); } if(!checkCmdParam(command, cmdParam)){ logger.error("command parameter check failed!"); return null; } if(command.getScheduleTime() != null){ processInstance.setScheduleTime(command.getScheduleTime()); } processInstance.setHost(host); ExecutionStatus runStatus = ExecutionStatus.RUNNING_EXEUTION; int runTime = processInstance.getRunTimes(); switch (commandType){ case START_PROCESS: break; case START_FAILURE_TASK_PROCESS: // find failed tasks and init these tasks List failedList = this.findTaskIdByInstanceState(processInstance.getId(), ExecutionStatus.FAILURE); List toleranceList = this.findTaskIdByInstanceState(processInstance.getId(), ExecutionStatus.NEED_FAULT_TOLERANCE); List killedList = this.findTaskIdByInstanceState(processInstance.getId(), ExecutionStatus.KILL); cmdParam.remove(Constants.CMDPARAM_RECOVERY_START_NODE_STRING); failedList.addAll(killedList); failedList.addAll(toleranceList); for(Integer taskId : failedList){ initTaskInstance(this.findTaskInstanceById(taskId)); } cmdParam.put(Constants.CMDPARAM_RECOVERY_START_NODE_STRING, String.join(Constants.COMMA, convertIntListToString(failedList))); processInstance.setCommandParam(JSONUtils.toJson(cmdParam)); processInstance.setRunTimes(runTime +1 ); break; case START_CURRENT_TASK_PROCESS: break; case RECOVER_WAITTING_THREAD: break; case RECOVER_SUSPENDED_PROCESS: // find pause tasks and init task's state cmdParam.remove(Constants.CMDPARAM_RECOVERY_START_NODE_STRING); List suspendedNodeList = this.findTaskIdByInstanceState(processInstance.getId(), ExecutionStatus.PAUSE); List stopNodeList = findTaskIdByInstanceState(processInstance.getId(), ExecutionStatus.KILL); suspendedNodeList.addAll(stopNodeList); for(Integer taskId : suspendedNodeList){ // initialize the pause state initTaskInstance(this.findTaskInstanceById(taskId)); } cmdParam.put(Constants.CMDPARAM_RECOVERY_START_NODE_STRING, String.join(",", convertIntListToString(suspendedNodeList))); processInstance.setCommandParam(JSONUtils.toJson(cmdParam)); processInstance.setRunTimes(runTime +1); break; case RECOVER_TOLERANCE_FAULT_PROCESS: // recover tolerance fault process processInstance.setRecovery(Flag.YES); runStatus = processInstance.getState(); break; case COMPLEMENT_DATA: // delete all the valid tasks when complement data List taskInstanceList = this.findValidTaskListByProcessId(processInstance.getId()); for(TaskInstance taskInstance : taskInstanceList){ taskInstance.setFlag(Flag.NO); this.updateTaskInstance(taskInstance); } initComplementDataParam(processDefinition, processInstance, cmdParam); break; case REPEAT_RUNNING: // delete the recover task names from command parameter if(cmdParam.containsKey(Constants.CMDPARAM_RECOVERY_START_NODE_STRING)){ cmdParam.remove(Constants.CMDPARAM_RECOVERY_START_NODE_STRING); processInstance.setCommandParam(JSONUtils.toJson(cmdParam)); } // delete all the valid tasks when repeat running List validTaskList = findValidTaskListByProcessId(processInstance.getId()); for(TaskInstance taskInstance : validTaskList){ taskInstance.setFlag(Flag.NO); updateTaskInstance(taskInstance); } processInstance.setStartTime(new Date()); processInstance.setEndTime(null); processInstance.setRunTimes(runTime +1); initComplementDataParam(processDefinition, processInstance, cmdParam); break; case SCHEDULER: break; default: break; } processInstance.setState(runStatus); return processInstance; } /** * return complement data if the process start with complement data * @param processInstance processInstance * @param command command * @return command type */ private CommandType getCommandTypeIfComplement(ProcessInstance processInstance, Command command){ if(CommandType.COMPLEMENT_DATA == processInstance.getCmdTypeIfComplement()){ return CommandType.COMPLEMENT_DATA; }else{ return command.getCommandType(); } } /** * initialize complement data parameters * @param processDefinition processDefinition * @param processInstance processInstance * @param cmdParam cmdParam */ private void initComplementDataParam(ProcessDefinition processDefinition, ProcessInstance processInstance, Map cmdParam) { if(!processInstance.isComplementData()){ return; } Date startComplementTime = DateUtils.parse(cmdParam.get(CMDPARAM_COMPLEMENT_DATA_START_DATE), YYYY_MM_DD_HH_MM_SS); if(Flag.NO == processInstance.getIsSubProcess()) { processInstance.setScheduleTime(startComplementTime); } processInstance.setGlobalParams(ParameterUtils.curingGlobalParams( processDefinition.getGlobalParamMap(), processDefinition.getGlobalParamList(), CommandType.COMPLEMENT_DATA, processInstance.getScheduleTime())); } /** * set sub work process parameters. * handle sub work process instance, update relation table and command parameters * set sub work process flag, extends parent work process command parameters * @param subProcessInstance subProcessInstance * @return process instance */ public ProcessInstance setSubProcessParam(ProcessInstance subProcessInstance){ String cmdParam = subProcessInstance.getCommandParam(); if(StringUtils.isEmpty(cmdParam)){ return subProcessInstance; } Map paramMap = JSONUtils.toMap(cmdParam); // write sub process id into cmd param. if(paramMap.containsKey(CMDPARAM_SUB_PROCESS) && CMDPARAM_EMPTY_SUB_PROCESS.equals(paramMap.get(CMDPARAM_SUB_PROCESS))){ paramMap.remove(CMDPARAM_SUB_PROCESS); paramMap.put(CMDPARAM_SUB_PROCESS, String.valueOf(subProcessInstance.getId())); subProcessInstance.setCommandParam(JSONUtils.toJson(paramMap)); subProcessInstance.setIsSubProcess(Flag.YES); this.saveProcessInstance(subProcessInstance); } // copy parent instance user def params to sub process.. String parentInstanceId = paramMap.get(CMDPARAM_SUB_PROCESS_PARENT_INSTANCE_ID); if(StringUtils.isNotEmpty(parentInstanceId)){ ProcessInstance parentInstance = findProcessInstanceDetailById(Integer.parseInt(parentInstanceId)); if(parentInstance != null){ subProcessInstance.setGlobalParams( joinGlobalParams(parentInstance.getGlobalParams(), subProcessInstance.getGlobalParams())); this.saveProcessInstance(subProcessInstance); }else{ logger.error("sub process command params error, cannot find parent instance: {} ", cmdParam); } } ProcessInstanceMap processInstanceMap = JSONUtils.parseObject(cmdParam, ProcessInstanceMap.class); if(processInstanceMap == null || processInstanceMap.getParentProcessInstanceId() == 0){ return subProcessInstance; } // update sub process id to process map table processInstanceMap.setProcessInstanceId(subProcessInstance.getId()); this.updateWorkProcessInstanceMap(processInstanceMap); return subProcessInstance; } /** * join parent global params into sub process. * only the keys doesn't in sub process global would be joined. * @param parentGlobalParams parentGlobalParams * @param subGlobalParams subGlobalParams * @return global params join */ private String joinGlobalParams(String parentGlobalParams, String subGlobalParams){ List parentPropertyList = JSONUtils.toList(parentGlobalParams, Property.class); List subPropertyList = JSONUtils.toList(subGlobalParams, Property.class); Map subMap = subPropertyList.stream().collect(Collectors.toMap(Property::getProp, Property::getValue)); for(Property parent : parentPropertyList){ if(!subMap.containsKey(parent.getProp())){ subPropertyList.add(parent); } } return JSONUtils.toJson(subPropertyList); } /** * initialize task instance * @param taskInstance taskInstance */ private void initTaskInstance(TaskInstance taskInstance){ if(!taskInstance.isSubProcess()){ if(taskInstance.getState().typeIsCancel() || taskInstance.getState().typeIsFailure()){ taskInstance.setFlag(Flag.NO); updateTaskInstance(taskInstance); return; } } taskInstance.setState(ExecutionStatus.SUBMITTED_SUCCESS); updateTaskInstance(taskInstance); } /** * submit task to db * submit sub process to command * @param taskInstance taskInstance * @return task instance */ @Transactional(rollbackFor = Exception.class) public TaskInstance submitTask(TaskInstance taskInstance){ ProcessInstance processInstance = this.findProcessInstanceDetailById(taskInstance.getProcessInstanceId()); logger.info("start submit task : {}, instance id:{}, state: {}", taskInstance.getName(), taskInstance.getProcessInstanceId(), processInstance.getState()); //submit to db TaskInstance task = submitTaskInstanceToDB(taskInstance, processInstance); if(task == null){ logger.error("end submit task to db error, task name:{}, process id:{} state: {} ", taskInstance.getName(), taskInstance.getProcessInstance(), processInstance.getState()); return task; } if(!task.getState().typeIsFinished()){ createSubWorkProcessCommand(processInstance, task); } logger.info("end submit task to db successfully:{} state:{} complete, instance id:{} state: {} ", taskInstance.getName(), task.getState(), processInstance.getId(), processInstance.getState()); return task; } /** * set work process instance map * @param parentInstance parentInstance * @param parentTask parentTask * @return process instance map */ private ProcessInstanceMap setProcessInstanceMap(ProcessInstance parentInstance, TaskInstance parentTask){ ProcessInstanceMap processMap = findWorkProcessMapByParent(parentInstance.getId(), parentTask.getId()); if(processMap != null){ return processMap; }else if(parentInstance.getCommandType() == CommandType.REPEAT_RUNNING || parentInstance.isComplementData()){ // update current task id to map // repeat running does not generate new sub process instance processMap = findPreviousTaskProcessMap(parentInstance, parentTask); if(processMap!= null){ processMap.setParentTaskInstanceId(parentTask.getId()); updateWorkProcessInstanceMap(processMap); return processMap; } } // new task processMap = new ProcessInstanceMap(); processMap.setParentProcessInstanceId(parentInstance.getId()); processMap.setParentTaskInstanceId(parentTask.getId()); createWorkProcessInstanceMap(processMap); return processMap; } /** * find previous task work process map. * @param parentProcessInstance parentProcessInstance * @param parentTask parentTask * @return process instance map */ private ProcessInstanceMap findPreviousTaskProcessMap(ProcessInstance parentProcessInstance, TaskInstance parentTask) { Integer preTaskId = 0; List preTaskList = this.findPreviousTaskListByWorkProcessId(parentProcessInstance.getId()); for(TaskInstance task : preTaskList){ if(task.getName().equals(parentTask.getName())){ preTaskId = task.getId(); ProcessInstanceMap map = findWorkProcessMapByParent(parentProcessInstance.getId(), preTaskId); if(map!=null){ return map; } } } logger.info("sub process instance is not found,parent task:{},parent instance:{}", parentTask.getId(), parentProcessInstance.getId()); return null; } /** * create sub work process command * @param parentProcessInstance parentProcessInstance * @param task task */ private void createSubWorkProcessCommand(ProcessInstance parentProcessInstance, TaskInstance task){ if(!task.isSubProcess()){ return; } ProcessInstanceMap instanceMap = setProcessInstanceMap(parentProcessInstance, task); TaskNode taskNode = JSONUtils.parseObject(task.getTaskJson(), TaskNode.class); Map subProcessParam = JSONUtils.toMap(taskNode.getParams()); Integer childDefineId = Integer.parseInt(subProcessParam.get(Constants.CMDPARAM_SUB_PROCESS_DEFINE_ID)); ProcessInstance childInstance = findSubProcessInstance(parentProcessInstance.getId(), task.getId()); CommandType fatherType = parentProcessInstance.getCommandType(); CommandType commandType = fatherType; if(childInstance == null || commandType == CommandType.REPEAT_RUNNING){ String fatherHistoryCommand = parentProcessInstance.getHistoryCmd(); // sub process must begin with schedule/complement data // if father begin with scheduler/complement data if(fatherHistoryCommand.startsWith(CommandType.SCHEDULER.toString()) || fatherHistoryCommand.startsWith(CommandType.COMPLEMENT_DATA.toString())){ commandType = CommandType.valueOf(fatherHistoryCommand.split(Constants.COMMA)[0]); } } if(childInstance != null){ childInstance.setState(ExecutionStatus.SUBMITTED_SUCCESS); updateProcessInstance(childInstance); } // set sub work process command String processMapStr = JSONUtils.toJson(instanceMap); Map cmdParam = JSONUtils.toMap(processMapStr); if(commandType == CommandType.COMPLEMENT_DATA || (childInstance != null && childInstance.isComplementData())){ Map parentParam = JSONUtils.toMap(parentProcessInstance.getCommandParam()); String endTime = parentParam.get(CMDPARAM_COMPLEMENT_DATA_END_DATE); String startTime = parentParam.get(CMDPARAM_COMPLEMENT_DATA_START_DATE); cmdParam.put(CMDPARAM_COMPLEMENT_DATA_END_DATE, endTime); cmdParam.put(CMDPARAM_COMPLEMENT_DATA_START_DATE, startTime); processMapStr = JSONUtils.toJson(cmdParam); } updateSubProcessDefinitionByParent(parentProcessInstance, childDefineId); Command command = new Command(); command.setWarningType(parentProcessInstance.getWarningType()); command.setWarningGroupId(parentProcessInstance.getWarningGroupId()); command.setFailureStrategy(parentProcessInstance.getFailureStrategy()); command.setProcessDefinitionId(childDefineId); command.setScheduleTime(parentProcessInstance.getScheduleTime()); command.setExecutorId(parentProcessInstance.getExecutorId()); command.setCommandParam(processMapStr); command.setCommandType(commandType); command.setProcessInstancePriority(parentProcessInstance.getProcessInstancePriority()); command.setWorkerGroup(parentProcessInstance.getWorkerGroup()); createCommand(command); logger.info("sub process command created: {} ", command.toString()); } /** * update sub process definition * @param parentProcessInstance parentProcessInstance * @param childDefinitionId childDefinitionId */ private void updateSubProcessDefinitionByParent(ProcessInstance parentProcessInstance, int childDefinitionId) { ProcessDefinition fatherDefinition = this.findProcessDefineById(parentProcessInstance.getProcessDefinitionId()); ProcessDefinition childDefinition = this.findProcessDefineById(childDefinitionId); if(childDefinition != null && fatherDefinition != null){ childDefinition.setReceivers(fatherDefinition.getReceivers()); childDefinition.setReceiversCc(fatherDefinition.getReceiversCc()); processDefineMapper.updateById(childDefinition); } } /** * submit task to mysql * @param taskInstance taskInstance * @param processInstance processInstance * @return task instance */ public TaskInstance submitTaskInstanceToDB(TaskInstance taskInstance, ProcessInstance processInstance){ ExecutionStatus processInstanceState = processInstance.getState(); if(taskInstance.getState().typeIsFailure()){ if(taskInstance.isSubProcess()){ taskInstance.setRetryTimes(taskInstance.getRetryTimes() + 1 ); }else { if( processInstanceState != ExecutionStatus.READY_STOP && processInstanceState != ExecutionStatus.READY_PAUSE){ // failure task set invalid taskInstance.setFlag(Flag.NO); updateTaskInstance(taskInstance); // crate new task instance if(taskInstance.getState() != ExecutionStatus.NEED_FAULT_TOLERANCE){ taskInstance.setRetryTimes(taskInstance.getRetryTimes() + 1 ); } taskInstance.setEndTime(null); taskInstance.setStartTime(new Date()); taskInstance.setFlag(Flag.YES); taskInstance.setHost(null); taskInstance.setId(0); } } } taskInstance.setExecutorId(processInstance.getExecutorId()); taskInstance.setProcessInstancePriority(processInstance.getProcessInstancePriority()); taskInstance.setState(getSubmitTaskState(taskInstance, processInstanceState)); taskInstance.setSubmitTime(new Date()); boolean saveResult = saveTaskInstance(taskInstance); if(!saveResult){ return null; } return taskInstance; } /** * ${processInstancePriority}_${processInstanceId}_${taskInstancePriority}_${taskInstanceId}_${task executed by ip1},${ip2}... * The tasks with the highest priority are selected by comparing the priorities of the above four levels from high to low. * @param taskInstance taskInstance * @return task zk queue str */ public String taskZkInfo(TaskInstance taskInstance) { String taskWorkerGroup = getTaskWorkerGroup(taskInstance); ProcessInstance processInstance = this.findProcessInstanceById(taskInstance.getProcessInstanceId()); if(processInstance == null){ logger.error("process instance is null. please check the task info, task id: " + taskInstance.getId()); return ""; } StringBuilder sb = new StringBuilder(100); sb.append(processInstance.getProcessInstancePriority().ordinal()).append(Constants.UNDERLINE) .append(taskInstance.getProcessInstanceId()).append(Constants.UNDERLINE) .append(taskInstance.getTaskInstancePriority().ordinal()).append(Constants.UNDERLINE) .append(taskInstance.getId()).append(Constants.UNDERLINE) .append(taskInstance.getWorkerGroup()); return sb.toString(); } /** * get submit task instance state by the work process state * cannot modify the task state when running/kill/submit success, or this * task instance is already exists in task queue . * return pause if work process state is ready pause * return stop if work process state is ready stop * if all of above are not satisfied, return submit success * * @param taskInstance taskInstance * @param processInstanceState processInstanceState * @return process instance state */ public ExecutionStatus getSubmitTaskState(TaskInstance taskInstance, ExecutionStatus processInstanceState){ ExecutionStatus state = taskInstance.getState(); if( // running or killed // the task already exists in task queue // return state state == ExecutionStatus.RUNNING_EXEUTION || state == ExecutionStatus.KILL || checkTaskExistsInTaskQueue(taskInstance) ){ return state; } //return pasue /stop if process instance state is ready pause / stop // or return submit success if( processInstanceState == ExecutionStatus.READY_PAUSE){ state = ExecutionStatus.PAUSE; }else if(processInstanceState == ExecutionStatus.READY_STOP || !checkProcessStrategy(taskInstance)) { state = ExecutionStatus.KILL; }else{ state = ExecutionStatus.SUBMITTED_SUCCESS; } return state; } /** * check process instance strategy * @param taskInstance taskInstance * @return check strategy result */ private boolean checkProcessStrategy(TaskInstance taskInstance){ ProcessInstance processInstance = this.findProcessInstanceById(taskInstance.getProcessInstanceId()); FailureStrategy failureStrategy = processInstance.getFailureStrategy(); if(failureStrategy == FailureStrategy.CONTINUE){ return true; } List taskInstances = this.findValidTaskListByProcessId(taskInstance.getProcessInstanceId()); for(TaskInstance task : taskInstances){ if(task.getState() == ExecutionStatus.FAILURE){ return false; } } return true; } /** * check the task instance existing in queue * @param taskInstance taskInstance * @return whether taskinstance exists queue */ public boolean checkTaskExistsInTaskQueue(TaskInstance taskInstance){ if(taskInstance.isSubProcess()){ return false; } String taskZkInfo = taskZkInfo(taskInstance); return false; } /** * create a new process instance * @param processInstance processInstance */ public void createProcessInstance(ProcessInstance processInstance){ if (processInstance != null){ processInstanceMapper.insert(processInstance); } } /** * insert or update work process instance to data base * @param processInstance processInstance */ public void saveProcessInstance(ProcessInstance processInstance){ if (processInstance == null){ logger.error("save error, process instance is null!"); return ; } if(processInstance.getId() != 0){ processInstanceMapper.updateById(processInstance); }else{ createProcessInstance(processInstance); } } /** * insert or update command * @param command command * @return save command result */ public int saveCommand(Command command){ if(command.getId() != 0){ return commandMapper.updateById(command); }else{ return commandMapper.insert(command); } } /** * insert or update task instance * @param taskInstance taskInstance * @return save task instance result */ public boolean saveTaskInstance(TaskInstance taskInstance){ if(taskInstance.getId() != 0){ return updateTaskInstance(taskInstance); }else{ return createTaskInstance(taskInstance); } } /** * insert task instance * @param taskInstance taskInstance * @return create task instance result */ public boolean createTaskInstance(TaskInstance taskInstance) { int count = taskInstanceMapper.insert(taskInstance); return count > 0; } /** * update task instance * @param taskInstance taskInstance * @return update task instance result */ public boolean updateTaskInstance(TaskInstance taskInstance){ int count = taskInstanceMapper.updateById(taskInstance); return count > 0; } /** * delete a command by id * @param id id */ public void delCommandByid(int id) { commandMapper.deleteById(id); } /** * find task instance by id * @param taskId task id * @return task intance */ public TaskInstance findTaskInstanceById(Integer taskId){ return taskInstanceMapper.selectById(taskId); } /** * package task instanceļ¼Œassociate processInstance and processDefine * @param taskInstId taskInstId * @return task instance */ public TaskInstance getTaskInstanceDetailByTaskId(int taskInstId){ // get task instance TaskInstance taskInstance = findTaskInstanceById(taskInstId); if(taskInstance == null){ return taskInstance; } // get process instance ProcessInstance processInstance = findProcessInstanceDetailById(taskInstance.getProcessInstanceId()); // get process define ProcessDefinition processDefine = findProcessDefineById(taskInstance.getProcessDefinitionId()); taskInstance.setProcessInstance(processInstance); taskInstance.setProcessDefine(processDefine); return taskInstance; } /** * get id list by task state * @param instanceId instanceId * @param state state * @return task instance states */ public List findTaskIdByInstanceState(int instanceId, ExecutionStatus state){ return taskInstanceMapper.queryTaskByProcessIdAndState(instanceId, state.ordinal()); } /** * find valid task list by process definition id * @param processInstanceId processInstanceId * @return task instance list */ public List findValidTaskListByProcessId(Integer processInstanceId){ return taskInstanceMapper.findValidTaskListByProcessId(processInstanceId, Flag.YES); } /** * find previous task list by work process id * @param processInstanceId processInstanceId * @return task instance list */ public List findPreviousTaskListByWorkProcessId(Integer processInstanceId){ return taskInstanceMapper.findValidTaskListByProcessId(processInstanceId, Flag.NO); } /** * update work process instance map * @param processInstanceMap processInstanceMap * @return update process instance result */ public int updateWorkProcessInstanceMap(ProcessInstanceMap processInstanceMap){ return processInstanceMapMapper.updateById(processInstanceMap); } /** * create work process instance map * @param processInstanceMap processInstanceMap * @return create process instance result */ public int createWorkProcessInstanceMap(ProcessInstanceMap processInstanceMap){ Integer count = 0; if(processInstanceMap !=null){ return processInstanceMapMapper.insert(processInstanceMap); } return count; } /** * find work process map by parent process id and parent task id. * @param parentWorkProcessId parentWorkProcessId * @param parentTaskId parentTaskId * @return process instance map */ public ProcessInstanceMap findWorkProcessMapByParent(Integer parentWorkProcessId, Integer parentTaskId){ return processInstanceMapMapper.queryByParentId(parentWorkProcessId, parentTaskId); } /** * delete work process map by parent process id * @param parentWorkProcessId parentWorkProcessId * @return delete process map result */ public int deleteWorkProcessMapByParentId(int parentWorkProcessId){ return processInstanceMapMapper.deleteByParentProcessId(parentWorkProcessId); } /** * find sub process instance * @param parentProcessId parentProcessId * @param parentTaskId parentTaskId * @return process instance */ public ProcessInstance findSubProcessInstance(Integer parentProcessId, Integer parentTaskId){ ProcessInstance processInstance = null; ProcessInstanceMap processInstanceMap = processInstanceMapMapper.queryByParentId(parentProcessId, parentTaskId); if(processInstanceMap == null || processInstanceMap.getProcessInstanceId() == 0){ return processInstance; } processInstance = findProcessInstanceById(processInstanceMap.getProcessInstanceId()); return processInstance; } /** * find parent process instance * @param subProcessId subProcessId * @return process instance */ public ProcessInstance findParentProcessInstance(Integer subProcessId) { ProcessInstance processInstance = null; ProcessInstanceMap processInstanceMap = processInstanceMapMapper.queryBySubProcessId(subProcessId); if(processInstanceMap == null || processInstanceMap.getProcessInstanceId() == 0){ return processInstance; } processInstance = findProcessInstanceById(processInstanceMap.getParentProcessInstanceId()); return processInstance; } /** * change task state * @param state state * @param startTime startTime * @param host host * @param executePath executePath * @param logPath logPath * @param taskInstId taskInstId */ public void changeTaskState(ExecutionStatus state, Date startTime, String host, String executePath, String logPath, int taskInstId) { TaskInstance taskInstance = taskInstanceMapper.selectById(taskInstId); taskInstance.setState(state); taskInstance.setStartTime(startTime); taskInstance.setHost(host); taskInstance.setExecutePath(executePath); taskInstance.setLogPath(logPath); saveTaskInstance(taskInstance); } /** * update process instance * @param processInstance processInstance * @return update process instance result */ public int updateProcessInstance(ProcessInstance processInstance){ return processInstanceMapper.updateById(processInstance); } /** * update the process instance * @param processInstanceId processInstanceId * @param processJson processJson * @param globalParams globalParams * @param scheduleTime scheduleTime * @param flag flag * @param locations locations * @param connects connects * @return update process instance result */ public int updateProcessInstance(Integer processInstanceId, String processJson, String globalParams, Date scheduleTime, Flag flag, String locations, String connects){ ProcessInstance processInstance = processInstanceMapper.queryDetailById(processInstanceId); if(processInstance!= null){ processInstance.setProcessInstanceJson(processJson); processInstance.setGlobalParams(globalParams); processInstance.setScheduleTime(scheduleTime); processInstance.setLocations(locations); processInstance.setConnects(connects); return processInstanceMapper.updateById(processInstance); } return 0; } /** * change task state * @param state state * @param endTime endTime * @param taskInstId taskInstId */ public void changeTaskState(ExecutionStatus state, Date endTime, int processId, String appIds, int taskInstId) { TaskInstance taskInstance = taskInstanceMapper.selectById(taskInstId); taskInstance.setPid(processId); taskInstance.setAppLink(appIds); taskInstance.setState(state); taskInstance.setEndTime(endTime); saveTaskInstance(taskInstance); } /** * convert integer list to string list * @param intList intList * @return string list */ public List convertIntListToString(List intList){ if(intList == null){ return new ArrayList<>(); } List result = new ArrayList(intList.size()); for(Integer intVar : intList){ result.add(String.valueOf(intVar)); } return result; } /** * update pid and app links field by task instance id * @param taskInstId taskInstId * @param pid pid * @param appLinks appLinks */ public void updatePidByTaskInstId(int taskInstId, int pid,String appLinks) { TaskInstance taskInstance = taskInstanceMapper.selectById(taskInstId); taskInstance.setPid(pid); taskInstance.setAppLink(appLinks); saveTaskInstance(taskInstance); } /** * query schedule by id * @param id id * @return schedule */ public Schedule querySchedule(int id) { return scheduleMapper.selectById(id); } /** * query Schedule by processDefinitionId * @param processDefinitionId processDefinitionId * @see Schedule */ public List queryReleaseSchedulerListByProcessDefinitionId(int processDefinitionId) { return scheduleMapper.queryReleaseSchedulerListByProcessDefinitionId(processDefinitionId); } /** * query need failover process instance * @param host host * @return process instance list */ public List queryNeedFailoverProcessInstances(String host){ return processInstanceMapper.queryByHostAndStatus(host, stateArray); } /** * process need failover process instance * @param processInstance processInstance */ @Transactional(rollbackFor = Exception.class) public void processNeedFailoverProcessInstances(ProcessInstance processInstance){ //1 update processInstance host is null processInstance.setHost("null"); processInstanceMapper.updateById(processInstance); //2 insert into recover command Command cmd = new Command(); cmd.setProcessDefinitionId(processInstance.getProcessDefinitionId()); cmd.setCommandParam(String.format("{\"%s\":%d}", Constants.CMDPARAM_RECOVER_PROCESS_ID_STRING, processInstance.getId())); cmd.setExecutorId(processInstance.getExecutorId()); cmd.setCommandType(CommandType.RECOVER_TOLERANCE_FAULT_PROCESS); createCommand(cmd); } /** * query all need failover task instances by host * @param host host * @return task instance list */ public List queryNeedFailoverTaskInstances(String host){ return taskInstanceMapper.queryByHostAndStatus(host, stateArray); } /** * find data source by id * @param id id * @return datasource */ public DataSource findDataSourceById(int id){ return dataSourceMapper.selectById(id); } /** * update process instance state by id * @param processInstanceId processInstanceId * @param executionStatus executionStatus * @return update process result */ public int updateProcessInstanceState(Integer processInstanceId, ExecutionStatus executionStatus) { ProcessInstance instance = processInstanceMapper.selectById(processInstanceId); instance.setState(executionStatus); return processInstanceMapper.updateById(instance); } /** * find process instance by the task id * @param taskId taskId * @return process instance */ public ProcessInstance findProcessInstanceByTaskId(int taskId){ TaskInstance taskInstance = taskInstanceMapper.selectById(taskId); if(taskInstance!= null){ return processInstanceMapper.selectById(taskInstance.getProcessInstanceId()); } return null; } /** * find udf function list by id list string * @param ids ids * @return udf function list */ public List queryUdfFunListByids(int[] ids){ return udfFuncMapper.queryUdfByIdStr(ids, null); } /** * find tenant code by resource name * @param resName resource name * @param resourceType resource type * @return tenant code */ public String queryTenantCodeByResName(String resName,ResourceType resourceType){ return resourceMapper.queryTenantCodeByResourceName(resName, resourceType.ordinal()); } /** * find schedule list by process define id. * @param ids ids * @return schedule list */ public List selectAllByProcessDefineId(int[] ids){ return scheduleMapper.selectAllByProcessDefineArray( ids); } /** * get dependency cycle by work process define id and scheduler fire time * @param masterId masterId * @param processDefinitionId processDefinitionId * @param scheduledFireTime the time the task schedule is expected to trigger * @return CycleDependency * @throws Exception if error throws Exception */ public CycleDependency getCycleDependency(int masterId, int processDefinitionId, Date scheduledFireTime) throws Exception { List list = getCycleDependencies(masterId,new int[]{processDefinitionId},scheduledFireTime); return list.size()>0 ? list.get(0) : null; } /** * get dependency cycle list by work process define id list and scheduler fire time * @param masterId masterId * @param ids ids * @param scheduledFireTime the time the task schedule is expected to trigger * @return CycleDependency list * @throws Exception if error throws Exception */ public List getCycleDependencies(int masterId,int[] ids,Date scheduledFireTime) throws Exception { List cycleDependencyList = new ArrayList(); if(ArrayUtils.isEmpty(ids)){ logger.warn("ids[] is empty!is invalid!"); return cycleDependencyList; } if(scheduledFireTime == null){ logger.warn("scheduledFireTime is null!is invalid!"); return cycleDependencyList; } String strCrontab = ""; CronExpression depCronExpression; Cron depCron; List list; List schedules = this.selectAllByProcessDefineId(ids); // for all scheduling information for(Schedule depSchedule:schedules){ strCrontab = depSchedule.getCrontab(); depCronExpression = CronUtils.parse2CronExpression(strCrontab); depCron = CronUtils.parse2Cron(strCrontab); CycleEnum cycleEnum = CronUtils.getMiniCycle(depCron); if(cycleEnum == null){ logger.error("{} is not valid",strCrontab); continue; } Calendar calendar = Calendar.getInstance(); switch (cycleEnum){ /*case MINUTE: calendar.add(Calendar.MINUTE,-61);*/ case HOUR: calendar.add(Calendar.HOUR,-25); break; case DAY: calendar.add(Calendar.DATE,-32); break; case WEEK: calendar.add(Calendar.DATE,-32); break; case MONTH: calendar.add(Calendar.MONTH,-13); break; default: logger.warn("Dependent process definition's cycleEnum is {},not support!!", cycleEnum.name()); continue; } Date start = calendar.getTime(); if(depSchedule.getProcessDefinitionId() == masterId){ list = CronUtils.getSelfFireDateList(start, scheduledFireTime, depCronExpression); }else { list = CronUtils.getFireDateList(start, scheduledFireTime, depCronExpression); } if(list.size()>=1){ start = list.get(list.size()-1); CycleDependency dependency = new CycleDependency(depSchedule.getProcessDefinitionId(),start, CronUtils.getExpirationTime(start, cycleEnum), cycleEnum); cycleDependencyList.add(dependency); } } return cycleDependencyList; } /** * find last scheduler process instance in the date interval * @param definitionId definitionId * @param dateInterval dateInterval * @return process instance */ public ProcessInstance findLastSchedulerProcessInterval(int definitionId, DateInterval dateInterval) { return processInstanceMapper.queryLastSchedulerProcess(definitionId, dateInterval.getStartTime(), dateInterval.getEndTime()); } /** * find last manual process instance interval * @param definitionId process definition id * @param dateInterval dateInterval * @return process instance */ public ProcessInstance findLastManualProcessInterval(int definitionId, DateInterval dateInterval) { return processInstanceMapper.queryLastManualProcess(definitionId, dateInterval.getStartTime(), dateInterval.getEndTime()); } /** * find last running process instance * @param definitionId process definition id * @param startTime start time * @param endTime end time * @return process instance */ public ProcessInstance findLastRunningProcess(int definitionId, Date startTime, Date endTime) { return processInstanceMapper.queryLastRunningProcess(definitionId, startTime, endTime, stateArray); } /** * query user queue by process instance id * @param processInstanceId processInstanceId * @return queue */ public String queryUserQueueByProcessInstanceId(int processInstanceId){ String queue = ""; ProcessInstance processInstance = processInstanceMapper.selectById(processInstanceId); if(processInstance == null){ return queue; } User executor = userMapper.selectById(processInstance.getExecutorId()); if(executor != null){ queue = executor.getQueue(); } return queue; } /** * get task worker group * @param taskInstance taskInstance * @return workerGroupId */ public String getTaskWorkerGroup(TaskInstance taskInstance) { String workerGroup = taskInstance.getWorkerGroup(); if(StringUtils.isNotBlank(workerGroup)){ return workerGroup; } int processInstanceId = taskInstance.getProcessInstanceId(); ProcessInstance processInstance = findProcessInstanceById(processInstanceId); if(processInstance != null){ return processInstance.getWorkerGroup(); } logger.info("task : {} will use default worker group", taskInstance.getId()); return Constants.DEFAULT_WORKER_GROUP; } /** * get have perm project list * @param userId userId * @return project list */ public List getProjectListHavePerm(int userId){ List createProjects = projectMapper.queryProjectCreatedByUser(userId); List authedProjects = projectMapper.queryAuthedProjectListByUserId(userId); if(createProjects == null){ createProjects = new ArrayList<>(); } if(authedProjects != null){ createProjects.addAll(authedProjects); } return createProjects; } /** * get have perm project ids * @param userId userId * @return project ids */ public List getProjectIdListHavePerm(int userId){ List projectIdList = new ArrayList<>(); for(Project project : getProjectListHavePerm(userId)){ projectIdList.add(project.getId()); } return projectIdList; } /** * list unauthorized udf function * @param userId user id * @param needChecks data source id array * @return unauthorized udf function list */ public List listUnauthorized(int userId,T[] needChecks,AuthorizationType authorizationType){ List resultList = new ArrayList(); if (!ArrayUtils.isEmpty(needChecks)) { Set originResSet = new HashSet(Arrays.asList(needChecks)); switch (authorizationType){ case RESOURCE_FILE_ID: Set authorizedResourceFiles = resourceMapper.listAuthorizedResourceById(userId, needChecks).stream().map(t -> t.getId()).collect(toSet()); originResSet.removeAll(authorizedResourceFiles); break; case RESOURCE_FILE_NAME: Set authorizedResources = resourceMapper.listAuthorizedResource(userId, needChecks).stream().map(t -> t.getFullName()).collect(toSet()); originResSet.removeAll(authorizedResources); break; case UDF_FILE: Set authorizedUdfFiles = resourceMapper.listAuthorizedResourceById(userId, needChecks).stream().map(t -> t.getId()).collect(toSet()); originResSet.removeAll(authorizedUdfFiles); break; case DATASOURCE: Set authorizedDatasources = dataSourceMapper.listAuthorizedDataSource(userId,needChecks).stream().map(t -> t.getId()).collect(toSet()); originResSet.removeAll(authorizedDatasources); break; case UDF: Set authorizedUdfs = udfFuncMapper.listAuthorizedUdfFunc(userId, needChecks).stream().map(t -> t.getId()).collect(toSet()); originResSet.removeAll(authorizedUdfs); break; } resultList.addAll(originResSet); } return resultList; } /** * get user by user id * @param userId user id * @return User */ public User getUserById(int userId){ return userMapper.queryDetailsById(userId); } /** * get resource by resoruce id * @param resoruceId resource id * @return Resource */ public Resource getResourceById(int resoruceId){ return resourceMapper.selectById(resoruceId); } /** * list resources by ids * @param resIds resIds * @return resource list */ public List listResourceByIds(Integer[] resIds){ return resourceMapper.listResourceByIds(resIds); } /** * format task app id in task instance * @param taskInstance * @return */ public String formatTaskAppId(TaskInstance taskInstance){ ProcessDefinition definition = this.findProcessDefineById(taskInstance.getProcessDefinitionId()); ProcessInstance processInstanceById = this.findProcessInstanceById(taskInstance.getProcessInstanceId()); if(definition == null || processInstanceById == null){ return ""; } return String.format("%s_%s_%s", definition.getId(), processInstanceById.getId(), taskInstance.getId()); } }