[Cherry-pick-2.0.3] 20220107 (#7871)
* cherry-pick * fix bug_7629 (#7630) * fix bug_7564 (#7625) * fix bug_7512 (#7716) * [Fix-7459][Sqoop] running error in parallel (#7752) * fix bug_7459 * fix bug_7459 * fix bug_7459 * fix bug_7459 * fix bug_7459 Co-authored-by: SbloodyS <sbloodys@qq.com> * [Feature-7576][Master] Optimize complement task's date (#7585) * feature_7576 * feature_7576 * feature 7576 * feature 7576 * [Fix-7767]Task instance is not deleted while deleting the process instance (#7768) * fix bug_7767 * fix bug_7767 * fix bug_7767 * fix bug_7767 * fix bug_7767 * [Feature-5951][Improvement][UI] When creating an alarm instance, the alarm instance name input box prompts optimization (#7770) * cherry-pick * [Fix-7773][Api] malform batchDeleteProcessInstanceByIds log output (#7774) * bug_7773 * bug_7773 * bug_7773 * bug_7773 * bug_7773 * [Feature-7777][UI] process definition page add create username (#7778) * feature_7777 * fix bug_7499 (#7739) Co-authored-by: SbloodyS <sbloodys@qq.com> * fix conflict * fix conflict * fix mapState never used error * fix bug_7789 (#7790) Co-authored-by: SbloodyS <sbloodys@qq.com> Co-authored-by: SbloodyS <sbloodys@qq.com> Co-authored-by: wangyizhi <wangyizhi1_yewu@cmss.chinamobile.com>
This commit is contained in:
parent
5592e7bb7b
commit
be86eaf357
|
|
@ -23,6 +23,7 @@ import static org.apache.dolphinscheduler.api.enums.Status.START_PROCESS_INSTANC
|
|||
|
||||
import org.apache.dolphinscheduler.api.aspect.AccessLogAnnotation;
|
||||
import org.apache.dolphinscheduler.api.enums.ExecuteType;
|
||||
import org.apache.dolphinscheduler.api.enums.Status;
|
||||
import org.apache.dolphinscheduler.api.exceptions.ApiException;
|
||||
import org.apache.dolphinscheduler.api.service.ExecutorService;
|
||||
import org.apache.dolphinscheduler.api.utils.Result;
|
||||
|
|
@ -36,8 +37,6 @@ import org.apache.dolphinscheduler.common.enums.WarningType;
|
|||
import org.apache.dolphinscheduler.common.utils.JSONUtils;
|
||||
import org.apache.dolphinscheduler.dao.entity.User;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
|
|
@ -55,6 +54,13 @@ import io.swagger.annotations.ApiOperation;
|
|||
import io.swagger.annotations.ApiParam;
|
||||
import springfox.documentation.annotations.ApiIgnore;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* executor controller
|
||||
*/
|
||||
|
|
@ -138,6 +144,100 @@ public class ExecutorController extends BaseController {
|
|||
return returnDataList(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* batch execute process instance
|
||||
* If any processDefinitionCode cannot be found, the failure information is returned and the status is set to
|
||||
* failed. The successful task will run normally and will not stop
|
||||
*
|
||||
* @param loginUser login user
|
||||
* @param projectCode project code
|
||||
* @param processDefinitionCodes process definition codes
|
||||
* @param scheduleTime schedule time
|
||||
* @param failureStrategy failure strategy
|
||||
* @param startNodeList start nodes list
|
||||
* @param taskDependType task depend type
|
||||
* @param execType execute type
|
||||
* @param warningType warning type
|
||||
* @param warningGroupId warning group id
|
||||
* @param runMode run mode
|
||||
* @param processInstancePriority process instance priority
|
||||
* @param workerGroup worker group
|
||||
* @param timeout timeout
|
||||
* @param expectedParallelismNumber the expected parallelism number when execute complement in parallel mode
|
||||
* @return start process result code
|
||||
*/
|
||||
@ApiOperation(value = "batchStartProcessInstance", notes = "BATCH_RUN_PROCESS_INSTANCE_NOTES")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "processDefinitionCodes", value = "PROCESS_DEFINITION_CODES", required = true, dataType = "String", example = "1,2,3"),
|
||||
@ApiImplicitParam(name = "scheduleTime", value = "SCHEDULE_TIME", required = true, dataType = "String"),
|
||||
@ApiImplicitParam(name = "failureStrategy", value = "FAILURE_STRATEGY", required = true, dataType = "FailureStrategy"),
|
||||
@ApiImplicitParam(name = "startNodeList", value = "START_NODE_LIST", dataType = "String"),
|
||||
@ApiImplicitParam(name = "taskDependType", value = "TASK_DEPEND_TYPE", dataType = "TaskDependType"),
|
||||
@ApiImplicitParam(name = "execType", value = "COMMAND_TYPE", dataType = "CommandType"),
|
||||
@ApiImplicitParam(name = "warningType", value = "WARNING_TYPE", required = true, dataType = "WarningType"),
|
||||
@ApiImplicitParam(name = "warningGroupId", value = "WARNING_GROUP_ID", required = true, dataType = "Int", example = "100"),
|
||||
@ApiImplicitParam(name = "runMode", value = "RUN_MODE", dataType = "RunMode"),
|
||||
@ApiImplicitParam(name = "processInstancePriority", value = "PROCESS_INSTANCE_PRIORITY", required = true, dataType = "Priority"),
|
||||
@ApiImplicitParam(name = "workerGroup", value = "WORKER_GROUP", dataType = "String", example = "default"),
|
||||
@ApiImplicitParam(name = "environmentCode", value = "ENVIRONMENT_CODE", dataType = "Long", example = "-1"),
|
||||
@ApiImplicitParam(name = "timeout", value = "TIMEOUT", dataType = "Int", example = "100"),
|
||||
@ApiImplicitParam(name = "expectedParallelismNumber", value = "EXPECTED_PARALLELISM_NUMBER", dataType = "Int", example = "8")
|
||||
})
|
||||
@PostMapping(value = "batch-start-process-instance")
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
@ApiException(START_PROCESS_INSTANCE_ERROR)
|
||||
@AccessLogAnnotation(ignoreRequestArgs = "loginUser")
|
||||
public Result batchStartProcessInstance(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
|
||||
@ApiParam(name = "projectCode", value = "PROJECT_CODE", required = true) @PathVariable long projectCode,
|
||||
@RequestParam(value = "processDefinitionCodes") String processDefinitionCodes,
|
||||
@RequestParam(value = "scheduleTime", required = false) String scheduleTime,
|
||||
@RequestParam(value = "failureStrategy", required = true) FailureStrategy failureStrategy,
|
||||
@RequestParam(value = "startNodeList", required = false) String startNodeList,
|
||||
@RequestParam(value = "taskDependType", required = false) TaskDependType taskDependType,
|
||||
@RequestParam(value = "execType", required = false) CommandType execType,
|
||||
@RequestParam(value = "warningType", required = true) WarningType warningType,
|
||||
@RequestParam(value = "warningGroupId", required = false) int warningGroupId,
|
||||
@RequestParam(value = "runMode", required = false) RunMode runMode,
|
||||
@RequestParam(value = "processInstancePriority", required = false) Priority processInstancePriority,
|
||||
@RequestParam(value = "workerGroup", required = false, defaultValue = "default") String workerGroup,
|
||||
@RequestParam(value = "environmentCode", required = false, defaultValue = "-1") Long environmentCode,
|
||||
@RequestParam(value = "timeout", required = false) Integer timeout,
|
||||
@RequestParam(value = "startParams", required = false) String startParams,
|
||||
@RequestParam(value = "expectedParallelismNumber", required = false) Integer expectedParallelismNumber,
|
||||
@RequestParam(value = "dryRun", defaultValue = "0", required = false) int dryRun) {
|
||||
|
||||
if (timeout == null) {
|
||||
timeout = Constants.MAX_TASK_TIMEOUT;
|
||||
}
|
||||
|
||||
Map<String, String> startParamMap = null;
|
||||
if (startParams != null) {
|
||||
startParamMap = JSONUtils.toMap(startParams);
|
||||
}
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
List<String> processDefinitionCodeArray = Arrays.asList(processDefinitionCodes.split(Constants.COMMA));
|
||||
List<String> startFailedProcessDefinitionCodeList = new ArrayList<>();
|
||||
|
||||
processDefinitionCodeArray = processDefinitionCodeArray.stream().distinct().collect(Collectors.toList());
|
||||
|
||||
for (String strProcessDefinitionCode : processDefinitionCodeArray) {
|
||||
long processDefinitionCode = Long.parseLong(strProcessDefinitionCode);
|
||||
result = execService.execProcessInstance(loginUser, projectCode, processDefinitionCode, scheduleTime, execType, failureStrategy,
|
||||
startNodeList, taskDependType, warningType, warningGroupId, runMode, processInstancePriority, workerGroup, environmentCode, timeout, startParamMap, expectedParallelismNumber, dryRun);
|
||||
|
||||
if (!Status.SUCCESS.equals(result.get(Constants.STATUS))) {
|
||||
startFailedProcessDefinitionCodeList.add(String.valueOf(processDefinitionCode));
|
||||
}
|
||||
}
|
||||
|
||||
if (!startFailedProcessDefinitionCodeList.isEmpty()) {
|
||||
putMsg(result, Status.BATCH_START_PROCESS_INSTANCE_ERROR, String.join(Constants.COMMA, startFailedProcessDefinitionCodeList));
|
||||
}
|
||||
|
||||
return returnDataList(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* do action to process instance:pause, stop, repeat, recover from pause, recover from stop
|
||||
*
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ public enum Status {
|
|||
NAME_EXIST(10135, "name {0} already exists", "名称[{0}]已存在"),
|
||||
SAVE_ERROR(10136, "save error", "保存错误"),
|
||||
DELETE_PROJECT_ERROR_DEFINES_NOT_NULL(10137, "please delete the process definitions in project first!", "请先删除全部工作流定义"),
|
||||
BATCH_DELETE_PROCESS_INSTANCE_BY_IDS_ERROR(10117, "batch delete process instance by ids {0} error", "批量删除工作流实例错误"),
|
||||
BATCH_DELETE_PROCESS_INSTANCE_BY_IDS_ERROR(10117, "batch delete process instance by ids {0} error", "批量删除工作流实例错误: {0}"),
|
||||
PREVIEW_SCHEDULE_ERROR(10139, "preview schedule error", "预览调度配置错误"),
|
||||
PARSE_TO_CRON_EXPRESSION_ERROR(10140, "parse cron to cron expression error", "解析调度表达式错误"),
|
||||
SCHEDULE_START_TIME_END_TIME_SAME(10141, "The start time must not be the same as the end", "开始时间不能和结束时间一样"),
|
||||
|
|
@ -250,6 +250,7 @@ public enum Status {
|
|||
COUNT_PROCESS_INSTANCE_STATE_ERROR(50012, "count process instance state error", "查询各状态流程实例数错误"),
|
||||
COUNT_PROCESS_DEFINITION_USER_ERROR(50013, "count process definition user error", "查询各用户流程定义数错误"),
|
||||
START_PROCESS_INSTANCE_ERROR(50014, "start process instance error", "运行工作流实例错误"),
|
||||
BATCH_START_PROCESS_INSTANCE_ERROR(50014, "batch start process instance error: {0}", "批量运行工作流实例错误: {0}"),
|
||||
EXECUTE_PROCESS_INSTANCE_ERROR(50015, "execute process instance error", "操作工作流实例错误"),
|
||||
CHECK_PROCESS_DEFINITION_ERROR(50016, "check process definition error", "工作流定义错误"),
|
||||
QUERY_RECIPIENTS_AND_COPYERS_BY_PROCESS_DEFINITION_ERROR(50017, "query recipients and copyers by process definition error", "查询收件人和抄送人错误"),
|
||||
|
|
|
|||
|
|
@ -571,6 +571,10 @@ public class ExecutorServiceImpl extends BaseServiceImpl implements ExecutorServ
|
|||
Map<String, String> cmdParam = JSONUtils.toMap(command.getCommandParam());
|
||||
switch (runMode) {
|
||||
case RUN_MODE_SERIAL: {
|
||||
if (start.after(end)) {
|
||||
logger.warn("The startDate {} is later than the endDate {}", start, end);
|
||||
break;
|
||||
}
|
||||
cmdParam.put(CMDPARAM_COMPLEMENT_DATA_START_DATE, DateUtils.dateToString(start));
|
||||
cmdParam.put(CMDPARAM_COMPLEMENT_DATA_END_DATE, DateUtils.dateToString(end));
|
||||
command.setCommandParam(JSONUtils.toJsonString(cmdParam));
|
||||
|
|
@ -578,26 +582,45 @@ public class ExecutorServiceImpl extends BaseServiceImpl implements ExecutorServ
|
|||
break;
|
||||
}
|
||||
case RUN_MODE_PARALLEL: {
|
||||
if (start.after(end)) {
|
||||
logger.warn("The startDate {} is later than the endDate {}", start, end);
|
||||
break;
|
||||
}
|
||||
|
||||
LinkedList<Date> listDate = new LinkedList<>();
|
||||
List<Schedule> schedules = processService.queryReleaseSchedulerListByProcessDefinitionCode(command.getProcessDefinitionCode());
|
||||
listDate.addAll(CronUtils.getSelfFireDateList(start, end, schedules));
|
||||
int listDateSize = listDate.size();
|
||||
createCount = listDate.size();
|
||||
if (!CollectionUtils.isEmpty(listDate)) {
|
||||
if (expectedParallelismNumber != null && expectedParallelismNumber != 0) {
|
||||
createCount = Math.min(listDate.size(), expectedParallelismNumber);
|
||||
if (listDateSize < createCount) {
|
||||
createCount = listDateSize;
|
||||
}
|
||||
}
|
||||
logger.info("In parallel mode, current expectedParallelismNumber:{}", createCount);
|
||||
|
||||
listDate.addLast(end);
|
||||
int chunkSize = listDate.size() / createCount;
|
||||
// Distribute the number of tasks equally to each command.
|
||||
// The last command with insufficient quantity will be assigned to the remaining tasks.
|
||||
int itemsPerCommand = (listDateSize / createCount);
|
||||
int remainingItems = (listDateSize % createCount);
|
||||
int startDateIndex = 0;
|
||||
int endDateIndex = 0;
|
||||
|
||||
for (int i = 0; i < createCount; i++) {
|
||||
int rangeStart = i == 0 ? i : (i * chunkSize);
|
||||
int rangeEnd = i == createCount - 1 ? listDate.size() - 1
|
||||
: rangeStart + chunkSize;
|
||||
for (int i = 1; i <= createCount; i++) {
|
||||
int extra = (i <= remainingItems) ? 1 : 0;
|
||||
int singleCommandItems = (itemsPerCommand + extra);
|
||||
|
||||
cmdParam.put(CMDPARAM_COMPLEMENT_DATA_START_DATE, DateUtils.dateToString(listDate.get(rangeStart)));
|
||||
cmdParam.put(CMDPARAM_COMPLEMENT_DATA_END_DATE, DateUtils.dateToString(listDate.get(rangeEnd)));
|
||||
if (i == 1) {
|
||||
endDateIndex += singleCommandItems - 1;
|
||||
} else {
|
||||
startDateIndex = endDateIndex + 1;
|
||||
endDateIndex += singleCommandItems;
|
||||
}
|
||||
|
||||
cmdParam.put(CMDPARAM_COMPLEMENT_DATA_START_DATE, DateUtils.dateToString(listDate.get(startDateIndex)));
|
||||
cmdParam.put(CMDPARAM_COMPLEMENT_DATA_END_DATE, DateUtils.dateToString(listDate.get(endDateIndex)));
|
||||
command.setCommandParam(JSONUtils.toJsonString(cmdParam));
|
||||
processService.createCommand(command);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -377,7 +377,7 @@ public class ProcessDefinitionServiceImpl extends BaseServiceImpl implements Pro
|
|||
processDefinitionNode.put("id", processDefinition.getId());
|
||||
processDefinitionNode.put("code", processDefinition.getCode());
|
||||
processDefinitionNode.put("name", processDefinition.getName());
|
||||
processDefinitionNode.put("projectCode", processDefinition.getCode());
|
||||
processDefinitionNode.put("projectCode", processDefinition.getProjectCode());
|
||||
arrayNode.add(processDefinitionNode);
|
||||
}
|
||||
result.put(Constants.DATA_LIST, arrayNode);
|
||||
|
|
|
|||
|
|
@ -629,13 +629,13 @@ public class ProcessInstanceServiceImpl extends BaseServiceImpl implements Proce
|
|||
}
|
||||
ProcessInstance processInstance = processService.findProcessInstanceDetailById(processInstanceId);
|
||||
if (null == processInstance) {
|
||||
putMsg(result, Status.PROCESS_INSTANCE_NOT_EXIST, processInstanceId);
|
||||
putMsg(result, Status.PROCESS_INSTANCE_NOT_EXIST, String.valueOf(processInstanceId));
|
||||
return result;
|
||||
}
|
||||
|
||||
ProcessDefinition processDefinition = processDefineMapper.queryByCode(processInstance.getProcessDefinitionCode());
|
||||
if (processDefinition != null && projectCode != processDefinition.getProjectCode()) {
|
||||
putMsg(result, Status.PROCESS_INSTANCE_NOT_EXIST, processInstanceId);
|
||||
putMsg(result, Status.PROCESS_INSTANCE_NOT_EXIST, String.valueOf(processInstanceId));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -649,6 +649,7 @@ public class ProcessInstanceServiceImpl extends BaseServiceImpl implements Proce
|
|||
|
||||
processService.deleteAllSubWorkProcessByParentId(processInstanceId);
|
||||
processService.deleteWorkProcessMapByParentId(processInstanceId);
|
||||
processService.deleteWorkTaskInstanceByProcessInstanceId(processInstanceId);
|
||||
|
||||
if (delete > 0) {
|
||||
putMsg(result, Status.SUCCESS);
|
||||
|
|
|
|||
|
|
@ -18,13 +18,14 @@
|
|||
QUERY_SCHEDULE_LIST_NOTES=query schedule list
|
||||
EXECUTE_PROCESS_TAG=execute process related operation
|
||||
PROCESS_INSTANCE_EXECUTOR_TAG=process instance executor related operation
|
||||
RUN_PROCESS_INSTANCE_NOTES=run process instance
|
||||
RUN_PROCESS_INSTANCE_NOTES=run process instance
|
||||
BATCH_RUN_PROCESS_INSTANCE_NOTES=batch run process instance
|
||||
START_NODE_LIST=start node list(node name)
|
||||
TASK_DEPEND_TYPE=task depend type
|
||||
COMMAND_TYPE=command type
|
||||
RUN_MODE=run mode
|
||||
TIMEOUT=timeout
|
||||
EXECUTE_ACTION_TO_PROCESS_INSTANCE_NOTES=execute action to process instance
|
||||
EXECUTE_ACTION_TO_PROCESS_INSTANCE_NOTES=execute action to process instance
|
||||
EXECUTE_TYPE=execute type
|
||||
START_CHECK_PROCESS_DEFINITION_NOTES=start check process definition
|
||||
GET_RECEIVER_CC_NOTES=query receiver cc
|
||||
|
|
|
|||
|
|
@ -17,7 +17,9 @@
|
|||
QUERY_SCHEDULE_LIST_NOTES=query schedule list
|
||||
EXECUTE_PROCESS_TAG=execute process related operation
|
||||
PROCESS_INSTANCE_EXECUTOR_TAG=process instance executor related operation
|
||||
RUN_PROCESS_INSTANCE_NOTES=run process instance
|
||||
RUN_PROCESS_INSTANCE_NOTES=run process instance
|
||||
BATCH_RUN_PROCESS_INSTANCE_NOTES=batch run process instance(If any processDefinitionCode cannot be found, the failure\
|
||||
\ information is returned and the status is set to failed. The successful task will run normally and will not stop)
|
||||
START_NODE_LIST=start node list(node name)
|
||||
TASK_DEPEND_TYPE=task depend type
|
||||
COMMAND_TYPE=command type
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ PROCESS_INSTANCE_EXECUTOR_TAG=流程实例执行相关操作
|
|||
UI_PLUGINS_TAG=UI插件相关操作
|
||||
WORK_FLOW_LINEAGE_TAG=工作流血缘相关操作
|
||||
RUN_PROCESS_INSTANCE_NOTES=运行流程实例
|
||||
BATCH_RUN_PROCESS_INSTANCE_NOTES=批量运行流程实例(其中有任意一个processDefinitionCode找不到,则返回失败信息并且状态置为失败,成功的任务会正常运行,不会停止)
|
||||
START_NODE_LIST=开始节点列表(节点name)
|
||||
TASK_DEPEND_TYPE=任务依赖类型
|
||||
COMMAND_TYPE=指令类型
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
package org.apache.dolphinscheduler.api.service;
|
||||
|
||||
import static org.apache.dolphinscheduler.common.Constants.CMDPARAM_COMPLEMENT_DATA_END_DATE;
|
||||
import static org.apache.dolphinscheduler.common.Constants.CMDPARAM_COMPLEMENT_DATA_START_DATE;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
|
@ -32,6 +34,8 @@ import org.apache.dolphinscheduler.common.enums.Priority;
|
|||
import org.apache.dolphinscheduler.common.enums.ReleaseState;
|
||||
import org.apache.dolphinscheduler.common.enums.RunMode;
|
||||
import org.apache.dolphinscheduler.common.model.Server;
|
||||
import org.apache.dolphinscheduler.common.utils.DateUtils;
|
||||
import org.apache.dolphinscheduler.common.utils.JSONUtils;
|
||||
import org.apache.dolphinscheduler.dao.entity.Command;
|
||||
import org.apache.dolphinscheduler.dao.entity.ProcessDefinition;
|
||||
import org.apache.dolphinscheduler.dao.entity.ProcessInstance;
|
||||
|
|
@ -340,22 +344,35 @@ public class ExecutorServiceTest {
|
|||
listDate.add(1);
|
||||
listDate.add(2);
|
||||
listDate.add(3);
|
||||
listDate.add(4);
|
||||
|
||||
int listDateSize = listDate.size();
|
||||
int createCount = Math.min(listDate.size(), expectedParallelismNumber);
|
||||
logger.info("In parallel mode, current expectedParallelismNumber:{}", createCount);
|
||||
|
||||
listDate.addLast(4);
|
||||
int chunkSize = listDate.size() / createCount;
|
||||
for (int i = 0; i < createCount; i++) {
|
||||
int rangeStart = i == 0 ? i : (i * chunkSize);
|
||||
int rangeEnd = i == createCount - 1 ? listDate.size() - 1 : rangeStart + chunkSize;
|
||||
logger.info("rangeStart:{}, rangeEnd:{}",rangeStart, rangeEnd);
|
||||
result.add(listDate.get(rangeStart) + "," + listDate.get(rangeEnd));
|
||||
int itemsPerCommand = (listDateSize / createCount);
|
||||
int remainingItems = (listDateSize % createCount);
|
||||
int startDateIndex = 0;
|
||||
int endDateIndex = 0;
|
||||
|
||||
for (int i = 1; i <= createCount; i++) {
|
||||
int extra = (i <= remainingItems) ? 1 : 0;
|
||||
int singleCommandItems = (itemsPerCommand + extra);
|
||||
|
||||
if (i == 1) {
|
||||
endDateIndex += singleCommandItems - 1;
|
||||
} else {
|
||||
startDateIndex = endDateIndex + 1;
|
||||
endDateIndex += singleCommandItems;
|
||||
}
|
||||
|
||||
logger.info("startDate:{}, endDate:{}", listDate.get(startDateIndex), listDate.get(endDateIndex));
|
||||
result.add(listDate.get(startDateIndex) + "," + listDate.get(endDateIndex));
|
||||
}
|
||||
|
||||
Assert.assertEquals("0,1", result.get(0));
|
||||
Assert.assertEquals("1,2", result.get(1));
|
||||
Assert.assertEquals("2,4", result.get(2));
|
||||
|
||||
Assert.assertEquals("2,3", result.get(1));
|
||||
Assert.assertEquals("4,4", result.get(2));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
package org.apache.dolphinscheduler.dao.upgrade;
|
||||
|
||||
import org.apache.dolphinscheduler.common.utils.ConnectionUtils;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
|
@ -32,7 +31,7 @@ import java.util.Map;
|
|||
* resource dao
|
||||
*/
|
||||
public class ResourceDao {
|
||||
public static final Logger logger = LoggerFactory.getLogger(ProcessDefinitionDao.class);
|
||||
public static final Logger logger = LoggerFactory.getLogger(ResourceDao.class);
|
||||
|
||||
/**
|
||||
* list all resources
|
||||
|
|
|
|||
|
|
@ -451,6 +451,25 @@ public class ProcessService {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* recursive delete all task instance by process instance id
|
||||
* @param processInstanceId
|
||||
*/
|
||||
public void deleteWorkTaskInstanceByProcessInstanceId(int processInstanceId) {
|
||||
List<TaskInstance> taskInstanceList = findValidTaskListByProcessId(processInstanceId);
|
||||
if (CollectionUtils.isEmpty(taskInstanceList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Integer> taskInstanceIdList = new ArrayList<>();
|
||||
|
||||
for (TaskInstance taskInstance : taskInstanceList) {
|
||||
taskInstanceIdList.add(taskInstance.getId());
|
||||
}
|
||||
|
||||
taskInstanceMapper.deleteBatchIds(taskInstanceIdList);
|
||||
}
|
||||
|
||||
/**
|
||||
* recursive query sub process definition id by parent id.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -191,9 +191,9 @@ public class CronUtils {
|
|||
return result;
|
||||
}
|
||||
|
||||
// support left closed and right open time interval (startDate <= N < endDate)
|
||||
// support left closed and right closed time interval (startDate <= N <= endDate)
|
||||
Date from = new Date(startTime.getTime() - Constants.SECOND_TIME_MILLIS);
|
||||
Date to = new Date(endTime.getTime() - Constants.SECOND_TIME_MILLIS);
|
||||
Date to = new Date(endTime.getTime() + Constants.SECOND_TIME_MILLIS);
|
||||
|
||||
List<Schedule> listSchedule = new ArrayList<>();
|
||||
listSchedule.addAll(schedules);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import static org.apache.dolphinscheduler.plugin.task.sqoop.SqoopConstants.HIVE_
|
|||
import static org.apache.dolphinscheduler.plugin.task.sqoop.SqoopConstants.HIVE_PARTITION_KEY;
|
||||
import static org.apache.dolphinscheduler.plugin.task.sqoop.SqoopConstants.HIVE_PARTITION_VALUE;
|
||||
import static org.apache.dolphinscheduler.plugin.task.sqoop.SqoopConstants.HIVE_TABLE;
|
||||
import static org.apache.dolphinscheduler.plugin.task.sqoop.SqoopConstants.TARGET_DIR;
|
||||
import static org.apache.dolphinscheduler.spi.task.TaskConstants.SPACE;
|
||||
|
||||
import org.apache.dolphinscheduler.plugin.task.sqoop.generator.ITargetGenerator;
|
||||
|
|
@ -91,6 +92,11 @@ public class HiveTargetGenerator implements ITargetGenerator {
|
|||
.append(SPACE).append(targetHiveParameter.getHivePartitionValue());
|
||||
}
|
||||
|
||||
if (StringUtils.isNotEmpty(targetHiveParameter.getHiveTargetDir())) {
|
||||
hiveTargetSb.append(SPACE).append(TARGET_DIR)
|
||||
.append(SPACE).append(targetHiveParameter.getHiveTargetDir());
|
||||
}
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error(String.format("Sqoop hive target params build failed: [%s]", e.getMessage()));
|
||||
|
|
|
|||
|
|
@ -54,6 +54,10 @@ public class TargetHiveParameter {
|
|||
* hive partition value
|
||||
*/
|
||||
private String hivePartitionValue;
|
||||
/**
|
||||
* hive target dir
|
||||
*/
|
||||
private String hiveTargetDir;
|
||||
|
||||
public String getHiveDatabase() {
|
||||
return hiveDatabase;
|
||||
|
|
@ -118,4 +122,12 @@ public class TargetHiveParameter {
|
|||
public void setHivePartitionValue(String hivePartitionValue) {
|
||||
this.hivePartitionValue = hivePartitionValue;
|
||||
}
|
||||
|
||||
public String getHiveTargetDir() {
|
||||
return hiveTargetDir;
|
||||
}
|
||||
|
||||
public void setHiveTargetDir(String hiveTargetDir) {
|
||||
this.hiveTargetDir = hiveTargetDir;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -529,7 +529,7 @@
|
|||
this.$router.push({
|
||||
name: 'task-instance',
|
||||
query: {
|
||||
processInstanceId: this.$route.params.code,
|
||||
processInstanceId: this.instanceId,
|
||||
taskName: taskName
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="clearfix list" v-if="enable">
|
||||
<div class="text-box">
|
||||
<span>{{$t('Waiting Dependent start')}}</span>
|
||||
|
|
@ -40,25 +41,44 @@
|
|||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="clearfix list" v-if="enable && waitStartTimeout.enable">
|
||||
<div class="text-box">
|
||||
<span>{{$t('Timeout period')}}</span>
|
||||
</div>
|
||||
<div class="cont-box">
|
||||
<label class="label-box">
|
||||
<span class="text-box">
|
||||
<span>{{$t('Timeout period')}}</span>
|
||||
</span>
|
||||
<el-input v-model="waitStartTimeout.interval" size="small" style="width: 100px;" :disabled="isDetails" maxlength="9">
|
||||
<span slot="append">{{$t('Minute')}}</span>
|
||||
</el-input>
|
||||
<span class="text-box">
|
||||
<span>{{$t('Check interval')}}</span>
|
||||
</span>
|
||||
<el-input v-model="waitStartTimeout.checkInterval" size="small" style="width: 100px;" :disabled="isDetails" maxlength="9">
|
||||
<span slot="append">{{$t('Minute')}}</span>
|
||||
</el-input>
|
||||
<span class="text-box">
|
||||
<span>{{$t('Timeout strategy')}}</span>
|
||||
</span>
|
||||
<div style="padding-top: 6px;">
|
||||
<div style="padding-top: 2px;">
|
||||
<el-input v-model="waitStartTimeout.interval" size="small" style="width: 100px;" :disabled="isDetails" maxlength="9">
|
||||
<span slot="append">{{$t('Minute')}}</span>
|
||||
</el-input>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="clearfix list" v-if="enable && waitStartTimeout.enable">
|
||||
<div class="text-box">
|
||||
<span>{{$t('Check interval')}}</span>
|
||||
</div>
|
||||
<div class="cont-box">
|
||||
<label class="label-box">
|
||||
<div style="padding-top: 2px;">
|
||||
<el-input v-model="waitStartTimeout.checkInterval" size="small" style="width: 100px;" :disabled="isDetails" maxlength="9">
|
||||
<span slot="append">{{$t('Minute')}}</span>
|
||||
</el-input>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="clearfix list" v-if="enable && waitStartTimeout.enable">
|
||||
<div class="text-box">
|
||||
<span>{{$t('Timeout strategy')}}</span>
|
||||
</div>
|
||||
<div class="cont-box">
|
||||
<label class="label-box">
|
||||
<div style="padding-top: 5px;">
|
||||
<el-checkbox-group size="small" v-model="waitStartTimeout.strategy">
|
||||
<el-checkbox label="FAILED" :disabled="true">{{$t('Timeout failure')}}</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
|
|
@ -66,6 +86,7 @@
|
|||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="clearfix list" v-if="enable">
|
||||
<div class="text-box">
|
||||
<span>{{$t('Waiting Dependent complete')}}</span>
|
||||
|
|
@ -78,19 +99,29 @@
|
|||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="clearfix list" v-if="enable && waitCompleteTimeout.enable">
|
||||
<div class="text-box">
|
||||
<span>{{$t('Timeout period')}}</span>
|
||||
</div>
|
||||
<div class="cont-box">
|
||||
<label class="label-box">
|
||||
<span class="text-box">
|
||||
<span>{{$t('Timeout period')}}</span>
|
||||
</span>
|
||||
<el-input v-model="waitCompleteTimeout.interval" size="small" style="width: 100px;" :disabled="isDetails" maxlength="9">
|
||||
<span slot="append">{{$t('Minute')}}</span>
|
||||
</el-input>
|
||||
<span class="text-box">
|
||||
<span>{{$t('Timeout strategy')}}</span>
|
||||
</span>
|
||||
<div style="padding-top: 6px;">
|
||||
<div style="padding-top: 2px;">
|
||||
<el-input v-model="waitCompleteTimeout.interval" size="small" style="width: 100px;" :disabled="isDetails" maxlength="9">
|
||||
<span slot="append">{{$t('Minute')}}</span>
|
||||
</el-input>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="clearfix list" v-if="enable && waitCompleteTimeout.enable">
|
||||
<div class="text-box">
|
||||
<span>{{$t('Timeout strategy')}}</span>
|
||||
</div>
|
||||
<div class="cont-box">
|
||||
<label class="label-box">
|
||||
<div style="padding-top: 5px;">
|
||||
<el-checkbox-group size="small" v-model="waitCompleteTimeout.strategy">
|
||||
<el-checkbox label="WARN" :disabled="isDetails">{{$t('Timeout alarm')}}</el-checkbox>
|
||||
<el-checkbox label="FAILED" :disabled="isDetails">{{$t('Timeout failure')}}</el-checkbox>
|
||||
|
|
|
|||
|
|
@ -20,7 +20,9 @@
|
|||
:disabled="isDetails"
|
||||
size="small"
|
||||
@change="_onChange"
|
||||
v-model="selectedValue">
|
||||
v-model="selectedValue"
|
||||
filterable
|
||||
allow-create>
|
||||
<el-input
|
||||
ref="input"
|
||||
slot="trigger"
|
||||
|
|
|
|||
|
|
@ -76,7 +76,8 @@
|
|||
props: {
|
||||
dependItemList: Array,
|
||||
index: Number,
|
||||
dependTaskList: Array
|
||||
dependTaskList: Array,
|
||||
projectDefinitionsCache: Object
|
||||
},
|
||||
model: {
|
||||
prop: 'dependItemList',
|
||||
|
|
@ -136,6 +137,9 @@
|
|||
})
|
||||
},
|
||||
_getProcessByProjectCode (code) {
|
||||
if (this.projectDefinitionsCache[code]) {
|
||||
return Promise.resolve(this.projectDefinitionsCache[code])
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
this.store.dispatch('dag/getProcessByProjectCode', code).then(res => {
|
||||
let definitionList = _.map(_.cloneDeep(res), v => {
|
||||
|
|
@ -144,6 +148,10 @@
|
|||
label: v.processDefinition.name
|
||||
}
|
||||
})
|
||||
this.$emit('addProjectDefinitionsCache', {
|
||||
projectCode: code,
|
||||
definitionList
|
||||
})
|
||||
resolve(definitionList)
|
||||
})
|
||||
})
|
||||
|
|
@ -281,16 +289,26 @@
|
|||
}
|
||||
})
|
||||
} else {
|
||||
// get definitionCode codes
|
||||
let codes = _.map(this.dependItemList, v => v.definitionCode).join(',')
|
||||
// get item list
|
||||
this._getDependItemList(codes, false).then(res => {
|
||||
_.map(this.dependItemList, (v, i) => {
|
||||
this._getProcessByProjectCode(v.projectCode).then(definitionList => {
|
||||
this.$set(this.dependItemList, i, this._rtOldParams(v.definitionCode, definitionList, [_.cloneDeep(DEP_ALL_TASK)].concat(_.map(res[v.definitionCode] || [], v => ({ code: v.code, name: v.name }))), v))
|
||||
// Get uniq definitionCodes and projectCodes
|
||||
const definitionCodes = _.uniq(this.dependItemList.map(dep => dep.definitionCode)).join(',')
|
||||
|
||||
// Query all tasks by definitionCodes, definitionCodes can cross projects
|
||||
this._getDependItemList(definitionCodes, false)
|
||||
.then(definitionTasks => {
|
||||
_.map(this.dependItemList, (dep, i) => {
|
||||
const definitionList = this.projectDefinitionsCache[dep.projectCode]
|
||||
const depTasksList = (definitionTasks[dep.definitionCode] || [])
|
||||
.map(task => ({ code: task.code, name: task.name }))
|
||||
.concat(_.cloneDeep(DEP_ALL_TASK))
|
||||
|
||||
this.$set(this.dependItemList, i, this._rtOldParams(
|
||||
dep.definitionCode,
|
||||
definitionList,
|
||||
depTasksList,
|
||||
dep
|
||||
))
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
<em v-if="isLoading" class="el-icon-loading as as-spin" data-toggle="tooltip" :title="$t('Add')"></em>
|
||||
</a>
|
||||
</div>
|
||||
<div class="dep-box">
|
||||
<div class="dep-box" v-if="cacheReady">
|
||||
<span
|
||||
class="dep-relation"
|
||||
@click="!isDetails && _setGlobalRelation()"
|
||||
|
|
@ -49,9 +49,11 @@
|
|||
</em>
|
||||
<m-depend-item-list
|
||||
:dependTaskList='dependTaskList'
|
||||
:projectDefinitionsCache='projectDefinitionsCache'
|
||||
v-model="el.dependItemList"
|
||||
@on-delete-all="_onDeleteAll"
|
||||
@getDependTaskList="getDependTaskList"
|
||||
@addProjectDefinitionsCache="addProjectDefinitionsCache"
|
||||
:index="$index">
|
||||
</m-depend-item-list>
|
||||
</div>
|
||||
|
|
@ -65,6 +67,7 @@
|
|||
import mListBox from './_source/listBox'
|
||||
import mDependItemList from './_source/dependItemList'
|
||||
import disabledState from '@/module/mixin/disabledState'
|
||||
import { mapActions } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'dependent',
|
||||
|
|
@ -72,7 +75,10 @@
|
|||
return {
|
||||
relation: 'AND',
|
||||
dependTaskList: [],
|
||||
isLoading: false
|
||||
isLoading: false,
|
||||
// Reduce repeated requests
|
||||
projectDefinitionsCache: {},
|
||||
cacheReady: false
|
||||
}
|
||||
},
|
||||
mixins: [disabledState],
|
||||
|
|
@ -80,6 +86,7 @@
|
|||
backfillItem: Object
|
||||
},
|
||||
methods: {
|
||||
...mapActions('dag', ['getProcessByProjectCode']),
|
||||
_addDep () {
|
||||
if (!this.isLoading) {
|
||||
this.isLoading = true
|
||||
|
|
@ -124,6 +131,25 @@
|
|||
})
|
||||
})
|
||||
return true
|
||||
},
|
||||
_getProcessByProjectCode (code) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.getProcessByProjectCode(code).then(res => {
|
||||
let definitionList = _.map(_.cloneDeep(res), v => {
|
||||
return {
|
||||
value: v.processDefinition.code,
|
||||
label: v.processDefinition.name
|
||||
}
|
||||
})
|
||||
resolve({
|
||||
definitionList,
|
||||
projectCode: code
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
addProjectDefinitionsCache ({ projectCode, definitionList }) {
|
||||
this.projectDefinitionsCache[projectCode] = definitionList
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
|
@ -150,6 +176,17 @@
|
|||
_.map(this.dependTaskList, v => _.map(v.dependItemList, v1 => {
|
||||
v1.state = dependentResult[`${v1.definitionId}-${v1.depTaskCode}-${v1.cycle}-${v1.dateValue}`] || defaultState
|
||||
}))
|
||||
// cache project definitions
|
||||
const projectCodes = _.uniq(_.flatten(this.dependTaskList.map(dep => dep.dependItemList.map(item => item.projectCode))))
|
||||
Promise.all(projectCodes.map(projectCode => this._getProcessByProjectCode(projectCode))).then((arr) => {
|
||||
arr.forEach((item) => {
|
||||
const { projectCode, definitionList } = item
|
||||
this.projectDefinitionsCache[projectCode] = definitionList
|
||||
})
|
||||
this.cacheReady = true
|
||||
})
|
||||
} else {
|
||||
this.cacheReady = true
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
|
|
|
|||
|
|
@ -325,6 +325,18 @@
|
|||
<el-switch v-model="targetHiveParams.hiveOverWrite" size="small"></el-switch>
|
||||
</div>
|
||||
</m-list-box>
|
||||
<m-list-box>
|
||||
<div slot="text">{{$t('Hive Target Dir')}}</div>
|
||||
<div slot="content">
|
||||
<el-input
|
||||
:disabled="isDetails"
|
||||
type="text"
|
||||
size="small"
|
||||
v-model="targetHiveParams.hiveTargetDir"
|
||||
:placeholder="$t('Please enter hive target dir')">
|
||||
</el-input>
|
||||
</div>
|
||||
</m-list-box>
|
||||
<m-list-box>
|
||||
<div slot="text">{{$t('ReplaceDelimiter')}}</div>
|
||||
<div slot="content">
|
||||
|
|
@ -691,6 +703,7 @@
|
|||
dropDelimiter: false,
|
||||
hiveOverWrite: true,
|
||||
replaceDelimiter: '',
|
||||
hiveTargetDir: '',
|
||||
hivePartitionKey: '',
|
||||
hivePartitionValue: ''
|
||||
},
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@
|
|||
<el-input
|
||||
type="input"
|
||||
v-model="host"
|
||||
maxlength="60"
|
||||
maxlength="255"
|
||||
size="small"
|
||||
:placeholder="$t('Please enter IP')">
|
||||
</el-input>
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@
|
|||
<span>{{scope.row.description | filterNull}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="userName" :label="$t('Create User')"></el-table-column>
|
||||
<el-table-column prop="modifyBy" :label="$t('Modify User')"></el-table-column>
|
||||
<el-table-column :label="$t('Timing state')">
|
||||
<template slot-scope="scope">
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
v-model="instanceName"
|
||||
maxlength="60"
|
||||
size="small"
|
||||
:placeholder="$t('Please enter group name')">
|
||||
:placeholder="$t('Please enter alarm plugin instance name')">
|
||||
</el-input>
|
||||
</template>
|
||||
</m-list-box-f>
|
||||
|
|
@ -108,7 +108,7 @@
|
|||
_verification () {
|
||||
// group name
|
||||
if (!this.instanceName.replace(/\s*/g, '')) {
|
||||
this.$message.warning(`${i18n.$t('Please enter group name')}`)
|
||||
this.$message.warning(`${i18n.$t('Please enter alarm plugin instance name')}`)
|
||||
return false
|
||||
}
|
||||
if (!this.pluginDefineId) {
|
||||
|
|
|
|||
|
|
@ -238,6 +238,7 @@ export default {
|
|||
'Instance parameter exception': 'Instance parameter exception',
|
||||
'Group Type': 'Group Type',
|
||||
'Alarm plugin instance': 'Alarm plugin instance',
|
||||
'Please enter alarm plugin instance name': 'Please enter alarm plugin instance name',
|
||||
'Select Alarm plugin instance': 'Please select an Alarm plugin instance',
|
||||
Remarks: 'Remarks',
|
||||
SMS: 'SMS',
|
||||
|
|
@ -606,6 +607,7 @@ export default {
|
|||
'Please enter Export Dir(required)': 'Please enter Export Dir(required)',
|
||||
'Please enter Hive Database(required)': 'Please enter Hive Databasec(required)',
|
||||
'Please enter Hive Table(required)': 'Please enter Hive Table(required)',
|
||||
'Please enter hive target dir': 'Please enter hive target dir',
|
||||
'Please enter Hive Partition Keys': 'Please enter Hive Partition Key',
|
||||
'Please enter Hive Partition Values': 'Please enter Partition Value',
|
||||
'Please enter Replace Delimiter': 'Please enter Replace Delimiter',
|
||||
|
|
|
|||
|
|
@ -237,6 +237,7 @@ export default {
|
|||
'Instance parameter exception': '实例参数异常',
|
||||
'Group Type': '组类型',
|
||||
'Alarm plugin instance': '告警插件实例',
|
||||
'Please enter alarm plugin instance name': '请输入告警实例名称',
|
||||
'Select Alarm plugin instance': '请选择告警插件实例',
|
||||
Remarks: '备注',
|
||||
SMS: '短信',
|
||||
|
|
@ -605,6 +606,7 @@ export default {
|
|||
'Please enter Export Dir(required)': '请输入数据源路径(必填)',
|
||||
'Please enter Hive Database(required)': '请输入Hive数据库(必填)',
|
||||
'Please enter Hive Table(required)': '请输入Hive表名(必填)',
|
||||
'Please enter hive target dir': '请输入Hive临时目录',
|
||||
'Please enter Hive Partition Keys': '请输入分区键',
|
||||
'Please enter Hive Partition Values': '请输入分区值',
|
||||
'Please enter Replace Delimiter': '请输入替换分隔符',
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ case $startStop in
|
|||
|
||||
(status)
|
||||
# more details about the status can be added later
|
||||
serverCount=`ps -ef |grep "$CLASS" |grep -v "grep" |wc -l`
|
||||
serverCount=`ps -ef | grep "$DOLPHINSCHEDULER_HOME" | grep "$CLASS" | grep -v "grep" | wc -l`
|
||||
state="STOP"
|
||||
# font color - red
|
||||
state="[ \033[1;31m $state \033[0m ]"
|
||||
|
|
|
|||
Loading…
Reference in New Issue