This commit is contained in:
JohnHuang 2024-06-11 22:32:48 -07:00 committed by GitHub
commit 07f37829a6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
221 changed files with 19735 additions and 94 deletions

View File

@ -77,18 +77,16 @@ alert:
sender-parallelism: 100
registry:
type: zookeeper
zookeeper:
namespace: dolphinscheduler
connect-string: localhost:2181
retry-policy:
base-sleep-time: 60ms
max-sleep: 300ms
max-retries: 5
session-timeout: 30s
connection-timeout: 9s
block-until-connected: 600ms
digest: ~
type: jdbc
term-refresh-interval: 2s
term-expire-times: 3
hikari-config:
jdbc-url: jdbc:postgresql://localhost:5432/dolphinscheduler
username: root
password: root
maximum-pool-size: 5
connection-timeout: 9000
idle-timeout: 600000
metrics:
enabled: true

View File

@ -46,11 +46,7 @@
</appender>
<root level="INFO">
<if condition="${DOCKER:-false}">
<then>
<appender-ref ref="STDOUT"/>
</then>
</if>
<appender-ref ref="STDOUT"/>
<appender-ref ref="ALERTLOGFILE"/>
</root>
</configuration>

View File

@ -77,6 +77,11 @@
<artifactId>dolphinscheduler-task-all</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dolphinscheduler</groupId>
<artifactId>dolphinscheduler-trigger-all</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dolphinscheduler</groupId>
<artifactId>dolphinscheduler-ui</artifactId>

View File

@ -28,6 +28,7 @@ import org.apache.dolphinscheduler.plugin.datasource.api.plugin.DataSourceProces
import org.apache.dolphinscheduler.plugin.storage.api.StorageConfiguration;
import org.apache.dolphinscheduler.plugin.task.api.TaskChannelFactory;
import org.apache.dolphinscheduler.plugin.task.api.TaskPluginManager;
import org.apache.dolphinscheduler.plugin.trigger.api.TriggerPluginManager;
import org.apache.dolphinscheduler.registry.api.RegistryConfiguration;
import org.apache.dolphinscheduler.service.ServiceConfiguration;
import org.apache.dolphinscheduler.spi.params.PluginParamsTransfer;
@ -70,6 +71,7 @@ public class ApiApplicationServer {
log.info("Received spring application context ready event will load taskPlugin and write to DB");
// install task plugin
TaskPluginManager.loadPlugin();
TriggerPluginManager.loadPlugin();
DataSourceProcessorProvider.initialize();
for (Map.Entry<String, TaskChannelFactory> entry : TaskPluginManager.getTaskChannelFactoryMap().entrySet()) {
String taskPluginName = entry.getKey();

View File

@ -0,0 +1,122 @@
/*
* 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.api.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.dolphinscheduler.api.audit.OperatorLog;
import org.apache.dolphinscheduler.api.audit.enums.AuditType;
import org.apache.dolphinscheduler.api.exceptions.ApiException;
import org.apache.dolphinscheduler.api.service.ExecutorService;
import org.apache.dolphinscheduler.api.service.TriggerDefinitionService;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.constants.Constants;
import org.apache.dolphinscheduler.common.enums.*;
import org.apache.dolphinscheduler.dao.entity.User;
import org.apache.dolphinscheduler.plugin.task.api.utils.ParameterUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import java.util.*;
import static org.apache.dolphinscheduler.api.enums.Status.*;
/**
* trigger definition controller
*/
@Tag(name = "TRIGGER_DEFINITION_TAG")
@RestController
@RequestMapping("projects/{projectCode}/trigger-definition")
@Slf4j
public class TriggerController extends BaseController {
@Autowired
private ExecutorService execService;
@Autowired
private TriggerDefinitionService triggerDefinitionService;
/**
* create trigger definition
*
* @param loginUser login user
* @param projectCode project code
* @param triggerDefinitionJson trigger definition json
* @return create result code
*/
@Operation(summary = "save", description = "CREATE_TRIGGER_DEFINITION_NOTES")
@Parameters({
@Parameter(name = "projectCode", description = "PROJECT_CODE", required = true, schema = @Schema(implementation = long.class)),
@Parameter(name = "triggerDefinitionJson", description = "TRIGGER_DEFINITION_JSON", required = true, schema = @Schema(implementation = String.class))
})
@PostMapping()
@ResponseStatus(HttpStatus.CREATED)
// change error code
@ApiException(CREATE_TASK_DEFINITION_ERROR)
// change audit type
@OperatorLog(auditType = AuditType.TASK_CREATE)
public Result createTriggerDefinition(@Parameter(hidden = true) @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
@Parameter(name = "projectCode", description = "PROJECT_CODE", required = true) @PathVariable long projectCode,
@RequestParam(value = "triggerDefinitionJson", required = true) String triggerDefinitionJson) {
Map<String, Object> result =
triggerDefinitionService.createTriggerDefinition(loginUser, projectCode, triggerDefinitionJson);
return returnDataList(result);
}
/**
* query task definition list paging
*
* @param loginUser login user
* @param projectCode project code
* @param searchTriggerName searchTaskName
* @param triggerType taskType
* @param pageNo page number
* @param pageSize page size
* @return task definition page
*/
@Operation(summary = "queryTaskDefinitionListPaging", description = "QUERY_TASK_DEFINITION_LIST_PAGING_NOTES")
@Parameters({
@Parameter(name = "projectCode", description = "PROJECT_CODE", required = false, schema = @Schema(implementation = long.class)),
@Parameter(name = "searchWorkflowName", description = "SEARCH_WORKFLOW_NAME", required = false, schema = @Schema(implementation = String.class)),
@Parameter(name = "searchTaskName", description = "SEARCH_TASK_NAME", required = false, schema = @Schema(implementation = String.class)),
@Parameter(name = "taskType", description = "TASK_TYPE", required = false, schema = @Schema(implementation = String.class, example = "SHELL")),
@Parameter(name = "taskExecuteType", description = "TASK_EXECUTE_TYPE", required = false, schema = @Schema(implementation = TaskExecuteType.class, example = "STREAM")),
@Parameter(name = "pageNo", description = "PAGE_NO", required = true, schema = @Schema(implementation = int.class, example = "1")),
@Parameter(name = "pageSize", description = "PAGE_SIZE", required = true, schema = @Schema(implementation = int.class, example = "10"))
})
@GetMapping()
@ResponseStatus(HttpStatus.OK)
@ApiException(QUERY_TASK_DEFINITION_LIST_PAGING_ERROR)
public Result queryTaskDefinitionListPaging(@Parameter(hidden = true) @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
@Parameter(name = "projectCode", description = "PROJECT_CODE", required = true) @PathVariable long projectCode,
@RequestParam(value = "searchTriggerName", required = false) String searchTriggerName,
@RequestParam(value = "triggerType", required = false) String triggerType,
@RequestParam("pageNo") Integer pageNo,
@RequestParam("pageSize") Integer pageSize) {
checkPageParams(pageNo, pageSize);
searchTriggerName = ParameterUtils.handleEscapes(searchTriggerName);
return triggerDefinitionService.queryTriggerDefinitionListPaging(loginUser, projectCode,
searchTriggerName, triggerType, pageNo, pageSize);
}
}

View File

@ -0,0 +1,24 @@
package org.apache.dolphinscheduler.api.service;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.enums.TaskExecuteType;
import org.apache.dolphinscheduler.dao.entity.User;
import java.util.Map;
/**
* trigger definition service
*/
public interface TriggerDefinitionService {
Map<String, Object> createTriggerDefinition(User loginUser,
long projectCode,
String triggerDefinitionJson);
Result queryTriggerDefinitionListPaging(User loginUser,
long projectCode,
String searchTriggerName,
String triggerType,
Integer pageNo,
Integer pageSize);
}

View File

@ -0,0 +1,149 @@
/*
* 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.api.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dolphinscheduler.api.dto.task.TaskCreateRequest;
import org.apache.dolphinscheduler.api.dto.task.TaskFilterRequest;
import org.apache.dolphinscheduler.api.dto.task.TaskUpdateRequest;
import org.apache.dolphinscheduler.api.dto.taskRelation.TaskRelationUpdateUpstreamRequest;
import org.apache.dolphinscheduler.api.dto.workflow.WorkflowUpdateRequest;
import org.apache.dolphinscheduler.api.enums.Status;
import org.apache.dolphinscheduler.api.exceptions.ServiceException;
import org.apache.dolphinscheduler.api.permission.PermissionCheck;
import org.apache.dolphinscheduler.api.service.*;
import org.apache.dolphinscheduler.api.utils.PageInfo;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.api.vo.TaskDefinitionVO;
import org.apache.dolphinscheduler.common.constants.Constants;
import org.apache.dolphinscheduler.common.enums.*;
import org.apache.dolphinscheduler.common.utils.CodeGenerateUtils;
import org.apache.dolphinscheduler.common.utils.JSONUtils;
import org.apache.dolphinscheduler.dao.entity.*;
import org.apache.dolphinscheduler.dao.mapper.*;
import org.apache.dolphinscheduler.dao.repository.ProcessTaskRelationLogDao;
import org.apache.dolphinscheduler.dao.repository.TaskDefinitionDao;
import org.apache.dolphinscheduler.plugin.task.api.TaskPluginManager;
import org.apache.dolphinscheduler.plugin.task.api.parameters.ParametersNode;
import org.apache.dolphinscheduler.service.process.ProcessService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import static org.apache.dolphinscheduler.api.constants.ApiFuncIdentificationConstant.*;
import static org.apache.dolphinscheduler.api.constants.ApiFuncIdentificationConstant.TASK_DEFINITION;
/**
* tenant service impl
*/
@Service
@Slf4j
public class TriggerDefinitionServiceImpl extends BaseServiceImpl implements TriggerDefinitionService {
@Autowired
private ProjectMapper projectMapper;
@Autowired
private ProjectService projectService;
@Autowired
private TaskDefinitionMapper taskDefinitionMapper;
@Autowired
private TriggerDefinitionMapper triggerDefinitionMapper;
@Autowired
private TaskDefinitionDao taskDefinitionDao;
@Autowired
private TaskDefinitionLogMapper taskDefinitionLogMapper;
@Autowired
private ProcessTaskRelationMapper processTaskRelationMapper;
@Autowired
private ProcessTaskRelationLogDao processTaskRelationLogDao;
@Autowired
private ProcessTaskRelationService processTaskRelationService;
@Autowired
private ProcessDefinitionMapper processDefinitionMapper;
@Autowired
private ProcessService processService;
@Autowired
private ProcessDefinitionService processDefinitionService;
@Autowired
private ProcessDefinitionLogMapper processDefinitionLogMapper;
@Transactional
@Override
public Map<String, Object> createTriggerDefinition(User loginUser,
long projectCode,
String triggerDefinitionJson) {
Project project = projectMapper.queryByCode(projectCode);
// check if user have write perm for project
Map<String, Object> result = new HashMap<>();
return result;
}
@Override
public Result queryTriggerDefinitionListPaging(User loginUser,
long projectCode,
String searchTriggerName,
String triggerType,
Integer pageNo,
Integer pageSize) {
Result result = new Result();
Project project = projectMapper.queryByCode(projectCode);
// check user access for project
Map<String, Object> checkResult =
projectService.checkProjectAndAuth(loginUser, project, projectCode, TASK_DEFINITION);
Status resultStatus = (Status) checkResult.get(Constants.STATUS);
if (resultStatus != Status.SUCCESS) {
putMsg(result, resultStatus);
return result;
}
triggerType = triggerType == null ? StringUtils.EMPTY : triggerType;
Page<TriggerMainInfo> page = new Page<>(pageNo, pageSize);
// first, query trigger code by page size
IPage<TriggerMainInfo> taskMainInfoIPage = triggerDefinitionMapper.queryDefinitionListPaging(page, projectCode,
searchTriggerName, triggerType);
PageInfo<TaskMainInfo> pageInfo = new PageInfo<>(pageNo, pageSize);
pageInfo.setTotal((int) taskMainInfoIPage.getTotal());
// pageInfo.setTotalList(taskMainInfoIPage.getRecords());
result.setData(pageInfo);
putMsg(result, Status.SUCCESS);
return result;
}
}

View File

@ -113,18 +113,16 @@ management:
application: ${spring.application.name}
registry:
type: zookeeper
zookeeper:
namespace: dolphinscheduler
connect-string: localhost:2181
retry-policy:
base-sleep-time: 60ms
max-sleep: 300ms
max-retries: 5
session-timeout: 60s
connection-timeout: 15s
block-until-connected: 15s
digest: ~
type: jdbc
term-refresh-interval: 2s
term-expire-times: 3
hikari-config:
jdbc-url: jdbc:postgresql://localhost:5432/dolphinscheduler
username: root
password: root
maximum-pool-size: 5
connection-timeout: 9000
idle-timeout: 600000
api:
audit-enable: false

View File

@ -51,11 +51,7 @@
<logger name="org.apache.hadoop" level="WARN"/>
<root level="INFO">
<if condition="${DOCKER:-false}">
<then>
<appender-ref ref="STDOUT"/>
</then>
</if>
<appender-ref ref="STDOUT" />
<appender-ref ref="APILOGFILE"/>
</root>
</configuration>

View File

@ -21,11 +21,11 @@ aws:
# AWSStaticCredentialsProvider: use the access key and secret key to authenticate
# InstanceProfileCredentialsProvider: use the IAM role to authenticate
credentials.provider.type: AWSStaticCredentialsProvider
access.key.id: accessKey123
access.key.secret: secretKey123
access.key.id: minioadmin
access.key.secret: minioadmin
region: us-east-1
bucket.name: dolphinscheduler
endpoint: http://s3:9000
endpoint: http://localhost:9000
emr:
# The AWS credentials provider type. support: AWSStaticCredentialsProvider, InstanceProfileCredentialsProvider
# AWSStaticCredentialsProvider: use the access key and secret key to authenticate

View File

@ -24,7 +24,7 @@ data.basedir.path=/tmp/dolphinscheduler
# resource storage type: LOCAL, HDFS, S3, OSS, GCS, ABS, OBS. LOCAL type is default type, and it's a specific type of HDFS with "resource.hdfs.fs.defaultFS = file:///" configuration
# please notice that LOCAL mode does not support reading and writing in distributed mode, which mean you can only use your resource in one machine, unless
# use shared file mount point
resource.storage.type=LOCAL
resource.storage.type=S3
# resource store on HDFS/S3 path, resource file will store to this base path, self configuration, please make sure the directory exists on hdfs and have read write permissions. "/dolphinscheduler" is recommended
resource.storage.upload.base.path=/dolphinscheduler

View File

@ -0,0 +1,93 @@
/*
* 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.dao.entity;
import java.util.Date;
import java.util.Objects;
import lombok.Data;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
@Data
@TableName("t_ds_trigger_definition")
public class TriggerDefinition {
/**
* id
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* code
*/
private long code;
/**
* name
*/
private String name;
/**
* description
*/
private String description;
/**
* project code
*/
private long projectCode;
/**
* trigger user id
*/
private int userId;
/**
* trigger type
*/
private String triggerType;
/**
* create time
*/
private Date createTime;
/**
* update time
*/
private Date updateTime;
public TriggerDefinition() {
}
public TriggerDefinition(long code) {
this.code = code;
}
public boolean equals(Object o) {
if (o == null) {
return false;
}
TriggerDefinition that = (TriggerDefinition) o;
return Objects.equals(name, that.name)
&& Objects.equals(description, that.description);
}
}

View File

@ -0,0 +1,99 @@
/*
* 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.dao.entity;
import java.io.Serializable;
import java.util.Date;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.Data;
import org.apache.dolphinscheduler.common.constants.Constants;
import org.apache.dolphinscheduler.common.enums.Flag;
import org.apache.dolphinscheduler.common.enums.Priority;
import org.apache.dolphinscheduler.common.enums.TaskExecuteType;
import org.apache.dolphinscheduler.common.utils.DateUtils;
import org.apache.dolphinscheduler.common.utils.JSONUtils;
import org.apache.dolphinscheduler.plugin.task.api.enums.TaskExecutionStatus;
import org.apache.dolphinscheduler.plugin.task.api.parameters.DependentParameters;
import org.apache.dolphinscheduler.plugin.task.api.parameters.SwitchParameters;
import static org.apache.dolphinscheduler.plugin.task.api.TaskConstants.*;
import static org.apache.dolphinscheduler.plugin.task.api.TaskConstants.TASK_TYPE_BLOCKING;
@Data
@TableName("t_ds_trigger_instance")
public class TriggerInstance implements Serializable {
/**
* id
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* task name
*/
private String name;
/**
* task type
*/
private String triggerType;
private int processInstanceId;
private String processInstanceName;
private Long projectCode;
private long triggerCode;
@TableField(exist = false)
private String processDefinitionName;
/**
* state
*/
private TaskExecutionStatus state;
/**
* task first submit time.
*/
private Date firstSubmitTime;
/**
* task submit time
*/
private Date submitTime;
/**
* task start time
*/
private Date startTime;
/**
* task end time
*/
private Date endTime;
}

View File

@ -0,0 +1,103 @@
/*
* 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.dao.entity;
import org.apache.dolphinscheduler.common.enums.ReleaseState;
import java.util.Date;
import java.util.Map;
import lombok.Data;
/**
* task main info
*/
@Data
public class TriggerMainInfo {
private long id;
/**
* task name
*/
private String taskName;
/**
* task code
*/
private long taskCode;
/**
* task version
*/
private int taskVersion;
/**
* task type
*/
private String taskType;
/**
* create time
*/
private Date taskCreateTime;
/**
* update time
*/
private Date taskUpdateTime;
/**
* projectCode
*/
private long projectCode;
/**
* processDefinitionCode
*/
private long processDefinitionCode;
/**
* processDefinitionVersion
*/
private int processDefinitionVersion;
/**
* processDefinitionName
*/
private String processDefinitionName;
/**
* processReleaseState
*/
private ReleaseState processReleaseState;
/**
* upstreamTaskMap(k:code,v:name)
*/
private Map<Long, String> upstreamTaskMap;
/**
* upstreamTaskCode
*/
private long upstreamTaskCode;
/**
* upstreamTaskName
*/
private String upstreamTaskName;
}

View File

@ -0,0 +1,26 @@
package org.apache.dolphinscheduler.dao.entity;
import lombok.Data;
import com.baomidou.mybatisplus.annotation.TableName;
@Data
@TableName("t_ds_trigger_offset")
public class TriggerOffset {
/**
* id
*/
private Integer id;
/**
* code
*/
private long code;
public TriggerOffset() {
}
public TriggerOffset(long code) {
this.code = code;
}
}

View File

@ -0,0 +1,90 @@
/*
* 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.dao.mapper;
import org.apache.dolphinscheduler.common.enums.TaskExecuteType;
import org.apache.dolphinscheduler.dao.entity.*;
import org.apache.dolphinscheduler.dao.model.WorkflowDefinitionCountDto;
import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Param;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
/**
* trigger definition mapper interface
*/
public interface TriggerDefinitionMapper extends BaseMapper<TriggerDefinition> {
/**
* query trigger definition by name
*
* @param projectCode projectCode
* @param processCode processCode
* @param name name
* @return trigger definition
*/
TriggerDefinition queryByName(@Param("projectCode") long projectCode,
@Param("processCode") long processCode,
@Param("name") String name);
/**
* query trigger definition by code
*
* @param code taskDefinitionCode
* @return trigger definition
*/
TriggerDefinition queryByCode(@Param("code") long code);
/**
* query all trigger definition list
*
* @param projectCode projectCode
* @return trigger definition list
*/
List<TriggerDefinition> queryAllDefinitionList(@Param("projectCode") long projectCode);
/**
* task main info page
*
* @param page page
* @param projectCode projectCode
* @param searchTriggerName searchTriggerName
* @param triggerType triggerType
* @return task main info IPage
*/
IPage<TriggerMainInfo> queryDefinitionListPaging(IPage<TriggerMainInfo> page,
@Param("projectCode") long projectCode,
@Param("searchTaskName") String searchTriggerName,
@Param("taskType") String triggerType);
/**
* delete trigger definition by code
*
* @param code code
* @return int
*/
int deleteByCode(@Param("code") long code);
}

View File

@ -0,0 +1,20 @@
package org.apache.dolphinscheduler.dao.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.apache.dolphinscheduler.common.enums.TaskExecuteType;
import org.apache.dolphinscheduler.dao.entity.*;
import org.apache.ibatis.annotations.Param;
import java.util.*;
public interface TriggerInstanceMapper extends BaseMapper<TriggerInstance> {
/**
* query trigger definition by code
*
* @param code taskDefinitionCode
* @return trigger definition
*/
TriggerInstance queryByCode(@Param("code") long code);
}

View File

@ -0,0 +1,16 @@
package org.apache.dolphinscheduler.dao.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.dolphinscheduler.dao.entity.*;
import org.apache.ibatis.annotations.Param;
public interface TriggerOffsetMapper extends BaseMapper<TriggerOffset> {
/**
* query trigger definition by code
*
* @param code taskDefinitionCode
* @return trigger definition
*/
TriggerOffset queryByCode(@Param("code") long code);
}

View File

@ -0,0 +1,27 @@
/*
* 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.dao.repository;
import org.apache.dolphinscheduler.dao.entity.TriggerDefinition;
/**
* Trigger Definition DAO
*/
public interface TriggerDefinitionDao extends IDao<TriggerDefinition> {
TriggerDefinition queryByCode(long triggerCode);
}

View File

@ -0,0 +1,10 @@
package org.apache.dolphinscheduler.dao.repository;
import org.apache.dolphinscheduler.dao.entity.TriggerInstance;
/**
* Trigger Instance DAO
*/
public interface TriggerInstanceDao extends IDao<TriggerInstance> {
TriggerInstance queryByCode(long triggerCode);
}

View File

@ -0,0 +1,50 @@
/*
* 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.dao.repository.impl;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.dolphinscheduler.dao.entity.*;
import org.apache.dolphinscheduler.dao.mapper.*;
import org.apache.dolphinscheduler.dao.repository.BaseDao;
import org.apache.dolphinscheduler.dao.repository.TriggerDefinitionDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
@Repository
@Slf4j
public class TriggerDefinitionDaoImpl extends BaseDao<TriggerDefinition, TriggerDefinitionMapper> implements TriggerDefinitionDao {
@Autowired
private ProcessDefinitionMapper processDefinitionMapper;
@Autowired
private ProcessTaskRelationLogMapper processTaskRelationLogMapper;
@Autowired
private TaskDefinitionLogMapper taskDefinitionLogMapper;
public TriggerDefinitionDaoImpl(@NonNull TriggerDefinitionMapper triggerDefinitionMapper) {
super(triggerDefinitionMapper);
}
@Override
public TriggerDefinition queryByCode(long triggerCode) {
return mybatisMapper.queryByCode(triggerCode);
}
}

View File

@ -0,0 +1,50 @@
/*
* 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.dao.repository.impl;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.dolphinscheduler.dao.entity.*;
import org.apache.dolphinscheduler.dao.mapper.*;
import org.apache.dolphinscheduler.dao.repository.BaseDao;
import org.apache.dolphinscheduler.dao.repository.TriggerInstanceDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
@Repository
@Slf4j
public class TriggerInstanceDaoImpl extends BaseDao<TriggerInstance, TriggerInstanceMapper> implements TriggerInstanceDao {
@Autowired
private ProcessDefinitionMapper processDefinitionMapper;
@Autowired
private ProcessTaskRelationLogMapper processTaskRelationLogMapper;
@Autowired
private TaskDefinitionLogMapper taskDefinitionLogMapper;
public TriggerInstanceDaoImpl(@NonNull TriggerInstanceMapper triggerInstanceMapper) {
super(triggerInstanceMapper);
}
@Override
public TriggerInstance queryByCode(long triggerCode) {
return mybatisMapper.queryByCode(triggerCode);
}
}

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
~ 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.
-->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="org.apache.dolphinscheduler.dao.mapper.TriggerDefinitionMapper">
<select id="queryDefinitionListPaging" resultType="org.apache.dolphinscheduler.dao.entity.TriggerMainInfo">
select td.code task_code
from t_ds_trigger_definition td
WHERE td.project_code = #{projectCode}
<if test="triggerType != ''">
and td.trigger_type = #{taskType}
</if>
<if test="searchTriggerName != null and searchTriggerName != ''">
and td.name like concat('%', #{searchTriggerName}, '%')
</if>
order by td.update_time desc
</select>
</mapper>

View File

@ -499,6 +499,57 @@ CREATE TABLE t_ds_task_definition
PRIMARY KEY (id, code)
);
-- ----------------------------
-- Table structure for t_ds_trigger_offset
-- ----------------------------
DROP TABLE IF EXISTS t_ds_trigger_offset CASCADE;
CREATE TABLE t_ds_trigger_offset
(
id int(11) NOT NULL,
code bigint(20) NOT NULL,
PRIMARY KEY (id, code)
);
-- ----------------------------
-- Table structure for t_ds_trigger_definition
-- ----------------------------
DROP TABLE IF EXISTS t_ds_trigger_definition CASCADE;
CREATE TABLE t_ds_trigger_definition
(
id int(11) NOT NULL AUTO_INCREMENT,
code bigint(20) NOT NULL,
name varchar(255) DEFAULT NULL,
description text,
project_code bigint(20) NOT NULL,
user_id int(11) DEFAULT NULL,
trigger_type varchar(50) NOT NULL,
trigger_params longtext,
create_time datetime NOT NULL,
update_time datetime DEFAULT NULL,
PRIMARY KEY (id, code)
);
-- ----------------------------
-- Table structure for t_ds_trigger_instance
-- ----------------------------
DROP TABLE IF EXISTS t_ds_trigger_instance CASCADE;
CREATE TABLE t_ds_trigger_instance
(
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(255) DEFAULT NULL,
trigger_type varchar(50) NOT NULL,
trigger_code bigint(20) NOT NULL,
process_instance_id int(11) DEFAULT NULL,
process_instance_name varchar(255) DEFAULT NULL,
project_code bigint(20) DEFAULT NULL,
state tinyint(4) DEFAULT NULL,
submit_time datetime DEFAULT NULL,
start_time datetime DEFAULT NULL,
end_time datetime DEFAULT NULL,
trigger_params longtext,
PRIMARY KEY (id)
);
-- ----------------------------
-- Table structure for t_ds_task_definition_log
-- ----------------------------
@ -2154,7 +2205,6 @@ CREATE TABLE t_ds_trigger_relation
UNIQUE KEY t_ds_trigger_relation_UN(trigger_type,job_id,trigger_code)
);
DROP TABLE IF EXISTS t_ds_relation_sub_workflow;
CREATE TABLE t_ds_relation_sub_workflow (
id BIGINT AUTO_INCREMENT NOT NULL,

View File

@ -939,6 +939,68 @@ CREATE TABLE `t_ds_task_instance` (
-- Records of t_ds_task_instance
-- ----------------------------
-- ----------------------------
-- Table structure for t_ds_trigger_offset
-- ----------------------------
DROP TABLE IF EXISTS `t_ds_trigger_offset`;
CREATE TABLE `t_ds_trigger_offset` (
`id` int(11) NOT NULL COMMENT 'self-increasing id',
`code` bigint(20) NOT NULL COMMENT 'encoding',
PRIMARY KEY (`id`,`code`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE = utf8_bin;
-- ----------------------------
-- Records of t_ds_trigger_offset
-- ----------------------------
-- ----------------------------
-- Table structure for t_ds_trigger_definition
-- ----------------------------
DROP TABLE IF EXISTS `t_ds_trigger_definition`;
CREATE TABLE `t_ds_trigger_definition` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'self-increasing id',
`code` bigint(20) NOT NULL COMMENT 'encoding',
`name` varchar(255) DEFAULT NULL COMMENT 'trigger definition name',
`description` text COMMENT 'description',
`project_code` bigint(20) NOT NULL COMMENT 'project code',
`user_id` int(11) DEFAULT NULL COMMENT 'trigger definition creator id',
`trigger_type` varchar(50) NOT NULL COMMENT 'trigger type',
`trigger_params` longtext COMMENT 'job custom parameters',
`create_time` datetime NOT NULL COMMENT 'create time',
`update_time` datetime NOT NULL COMMENT 'update time',
PRIMARY KEY (`id`,`code`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE = utf8_bin;
-- ----------------------------
-- Records of t_ds_trigger_definition
-- ----------------------------
-- ----------------------------
-- Table structure for t_ds_trigger_instance
-- ----------------------------
DROP TABLE IF EXISTS `t_ds_trigger_instance`;
CREATE TABLE `t_ds_trigger_instance` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'key',
`name` varchar(255) DEFAULT NULL COMMENT 'trigger name',
`trigger_type` varchar(50) NOT NULL COMMENT 'trigger type',
`trigger_code` bigint(20) NOT NULL COMMENT 'trigger definition code',
`process_instance_id` int(11) DEFAULT NULL COMMENT 'process instance id',
`process_instance_name` varchar(255) DEFAULT NULL COMMENT 'process instance name',
`project_code` bigint(20) DEFAULT NULL COMMENT 'project code',
`state` tinyint(4) DEFAULT NULL COMMENT 'Status: 0 commit succeeded, 1 running, 2 prepare to pause, 3 pause, 4 prepare to stop, 5 stop, 6 fail, 7 succeed, 8 need fault tolerance, 9 kill, 10 wait for thread, 11 wait for dependency to complete',
`submit_time` datetime DEFAULT NULL COMMENT 'trigger submit time',
`start_time` datetime DEFAULT NULL COMMENT 'trigger start time',
`end_time` datetime DEFAULT NULL COMMENT 'trigger end time',
`trigger_params` longtext COMMENT 'job custom parameters',
PRIMARY KEY (`id`),
KEY `process_instance_id` (`process_instance_id`) USING BTREE,
KEY `idx_code_version` (`task_code`, `task_definition_version`) USING BTREE,
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE = utf8_bin;
-- ----------------------------
-- Records of t_ds_trigger_instance
-- ----------------------------
-- ----------------------------
-- Table structure for t_ds_tenant
-- ----------------------------

View File

@ -419,6 +419,61 @@ CREATE TABLE t_ds_task_definition (
create index task_definition_index on t_ds_task_definition (project_code,id);
--
-- Table structure for table t_ds_trigger_offset
--
DROP TABLE IF EXISTS t_ds_trigger_offset;
CREATE TABLE t_ds_trigger_offset (
id int NOT NULL ,
code bigint NOT NULL,
PRIMARY KEY (id)
) ;
--
-- Table structure for table t_ds_trigger_definition
--
DROP TABLE IF EXISTS t_ds_trigger_definition;
CREATE TABLE t_ds_trigger_definition (
id int NOT NULL ,
code bigint NOT NULL,
name varchar(255) DEFAULT NULL ,
description text ,
project_code bigint DEFAULT NULL ,
user_id int DEFAULT NULL ,
trigger_type varchar(50) DEFAULT NULL ,
trigger_params text ,
create_time timestamp DEFAULT NULL ,
update_time timestamp DEFAULT NULL ,
PRIMARY KEY (id)
) ;
create index trigger_definition_index on t_ds_trigger_definition (project_code,id);
--
-- Table structure for table t_ds_trigger_instance
--
DROP TABLE IF EXISTS t_ds_trigger_instance;
CREATE TABLE t_ds_trigger_instance (
id int NOT NULL ,
name varchar(255) DEFAULT NULL ,
trigger_type varchar(50) DEFAULT NULL ,
trigger_code bigint NOT NULL,
process_instance_id int DEFAULT NULL ,
process_instance_name varchar(255) DEFAULT NULL,
project_code bigint DEFAULT NULL,
state int DEFAULT NULL ,
submit_time timestamp DEFAULT NULL ,
start_time timestamp DEFAULT NULL ,
end_time timestamp DEFAULT NULL ,
trigger_params text ,
PRIMARY KEY (id)
) ;
create index idx_trigger_instance_code_version on t_ds_trigger_instance (task_code, task_definition_version);
--
-- Table structure for table t_ds_task_definition_log
--
@ -838,6 +893,8 @@ CREATE TABLE t_ds_task_instance (
create index idx_task_instance_code_version on t_ds_task_instance (task_code, task_definition_version);
create index idx_cache_key on t_ds_task_instance (cache_key);
--
-- Table structure for table t_ds_tenant
--

View File

@ -0,0 +1,54 @@
/*
* 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.dao.mapper;
import java.util.Date;
import org.apache.dolphinscheduler.dao.BaseDaoTest;
import org.apache.dolphinscheduler.dao.entity.TaskDefinition;
import org.apache.dolphinscheduler.dao.entity.TriggerDefinition;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
public class TriggerDefinitionMapperTest extends BaseDaoTest {
@Autowired
private TriggerDefinitionMapper triggerDefinitionMapper;
public TriggerDefinition insertOne() {
return insertOne(99);
}
public TriggerDefinition insertOne(int userId) {
TriggerDefinition triggerDefinition = new TriggerDefinition();
triggerDefinition.setCode(888888L);
triggerDefinition.setName("unit-test");
triggerDefinition.setProjectCode(1L);
triggerDefinition.setUserId(userId);
triggerDefinition.setCreateTime(new Date());
triggerDefinition.setUpdateTime(new Date());
triggerDefinition.setTriggerType("unit-test");
triggerDefinitionMapper.insert(triggerDefinition);
return triggerDefinition;
}
@Test
public void testInsert() {
TriggerDefinition triggerDefinition = insertOne();
Assertions.assertNotEquals(0, triggerDefinition.getId().intValue());
}
}

View File

@ -0,0 +1,87 @@
/*
* 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.dao.mapper;
import java.util.Date;
import org.apache.dolphinscheduler.common.enums.WorkflowExecutionStatus;
import org.apache.dolphinscheduler.dao.BaseDaoTest;
import org.apache.dolphinscheduler.dao.entity.ProcessInstance;
import org.apache.dolphinscheduler.dao.entity.TriggerInstance;
import org.apache.dolphinscheduler.plugin.task.api.enums.TaskExecutionStatus;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
public class TriggerInstanceMapperTest extends BaseDaoTest {
@Autowired
private ProcessDefinitionMapper processDefinitionMapper;
@Autowired
private ProcessInstanceMapper processInstanceMapper;
@Autowired
private TriggerInstanceMapper triggerInstanceMapper;
/**
* insert
*
* @return ProcessInstance
*/
private ProcessInstance insertProcessInstance() {
ProcessInstance processInstance = new ProcessInstance();
processInstance.setId(1);
processInstance.setName("taskName");
processInstance.setState(WorkflowExecutionStatus.RUNNING_EXECUTION);
processInstance.setStartTime(new Date());
processInstance.setEndTime(new Date());
processInstance.setProcessDefinitionCode(1L);
processInstance.setProjectCode(1L);
processInstance.setTestFlag(0);
processInstanceMapper.insert(processInstance);
return processInstance;
}
/**
* construct a task instance and then insert
*/
private TriggerInstance insertTriggerInstance(int processInstanceId) {
TriggerInstance taskInstance = new TriggerInstance();
taskInstance.setName("us task");
taskInstance.setState(TaskExecutionStatus.RUNNING_EXECUTION);
taskInstance.setStartTime(new Date());
taskInstance.setEndTime(new Date());
taskInstance.setTriggerType("asd");
taskInstance.setProcessInstanceId(processInstanceId);
taskInstance.setProjectCode(1L);
triggerInstanceMapper.insert(taskInstance);
return taskInstance;
}
/**
* test update
*/
@Test
public void testUpdate() {
// insert ProcessInstance
ProcessInstance processInstance = insertProcessInstance();
// insert taskInstance
TriggerInstance triggerInstance = insertTriggerInstance(processInstance.getId());
}
}

View File

@ -0,0 +1,31 @@
package org.apache.dolphinscheduler.dao.mapper;
import org.apache.dolphinscheduler.dao.BaseDaoTest;
import org.apache.dolphinscheduler.dao.entity.TriggerOffset;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Date;
public class TriggerOffsetMapperTest extends BaseDaoTest {
@Autowired
private TriggerOffsetMapper triggerOffsetMapper;
public TriggerOffset insertOne() {
return insertOne(99);
}
public TriggerOffset insertOne(int userId) {
TriggerOffset triggerOffset = new TriggerOffset();
triggerOffset.setId(1);
triggerOffset.setCode(888888L);
return triggerOffset;
}
@Test
public void testInsert() {
TriggerOffset triggerDefinition = insertOne();
Assertions.assertNotEquals(0, triggerDefinition.getId().intValue());
}
}

View File

@ -69,6 +69,11 @@
<artifactId>dolphinscheduler-task-all</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dolphinscheduler</groupId>
<artifactId>dolphinscheduler-trigger-all</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dolphinscheduler</groupId>
<artifactId>dolphinscheduler-storage-all</artifactId>

View File

@ -29,6 +29,7 @@ import org.apache.dolphinscheduler.meter.metrics.SystemMetrics;
import org.apache.dolphinscheduler.plugin.datasource.api.plugin.DataSourceProcessorProvider;
import org.apache.dolphinscheduler.plugin.storage.api.StorageConfiguration;
import org.apache.dolphinscheduler.plugin.task.api.TaskPluginManager;
import org.apache.dolphinscheduler.plugin.trigger.api.TriggerPluginManager;
import org.apache.dolphinscheduler.registry.api.RegistryConfiguration;
import org.apache.dolphinscheduler.scheduler.api.SchedulerApi;
import org.apache.dolphinscheduler.server.master.metrics.MasterServerMetrics;
@ -38,6 +39,7 @@ import org.apache.dolphinscheduler.server.master.rpc.MasterRpcServer;
import org.apache.dolphinscheduler.server.master.runner.EventExecuteService;
import org.apache.dolphinscheduler.server.master.runner.FailoverExecuteThread;
import org.apache.dolphinscheduler.server.master.runner.MasterSchedulerBootstrap;
import org.apache.dolphinscheduler.server.master.runner.MasterTriggerBootstrap;
import org.apache.dolphinscheduler.server.master.runner.taskgroup.TaskGroupCoordinator;
import org.apache.dolphinscheduler.service.ServiceConfiguration;
import org.apache.dolphinscheduler.service.bean.SpringApplicationContext;
@ -70,6 +72,9 @@ public class MasterServer implements IStoppable {
@Autowired
private MasterSchedulerBootstrap masterSchedulerBootstrap;
@Autowired
private MasterTriggerBootstrap masterTriggerBootstrap;
@Autowired
private SchedulerApi schedulerApi;
@ -109,6 +114,7 @@ public class MasterServer implements IStoppable {
// install task plugin
TaskPluginManager.loadPlugin();
TriggerPluginManager.loadPlugin();
DataSourceProcessorProvider.initialize();
this.masterSlotManager.start();
@ -119,6 +125,8 @@ public class MasterServer implements IStoppable {
this.masterSchedulerBootstrap.start();
this.masterTriggerBootstrap.start();
this.eventExecuteService.start();
this.failoverExecuteThread.start();
@ -162,6 +170,7 @@ public class MasterServer implements IStoppable {
try (
SchedulerApi closedSchedulerApi = schedulerApi;
MasterSchedulerBootstrap closedSchedulerBootstrap = masterSchedulerBootstrap;
MasterTriggerBootstrap closedTriggerBootstrap = masterTriggerBootstrap;
MasterRpcServer closedRpcServer = masterRPCServer;
MasterRegistryClient closedMasterRegistryClient = masterRegistryClient;
// close spring Context and will invoke method with @PreDestroy annotation to destroy beans.

View File

@ -0,0 +1,151 @@
package org.apache.dolphinscheduler.server.master.runner;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.dolphinscheduler.common.constants.Constants;
import org.apache.dolphinscheduler.common.lifecycle.ServerLifeCycleManager;
import org.apache.dolphinscheduler.common.thread.BaseDaemonThread;
import org.apache.dolphinscheduler.common.thread.ThreadUtils;
import org.apache.dolphinscheduler.dao.entity.Command;
import org.apache.dolphinscheduler.dao.entity.ProcessInstance;
import org.apache.dolphinscheduler.meter.metrics.MetricsProvider;
import org.apache.dolphinscheduler.meter.metrics.SystemMetrics;
import org.apache.dolphinscheduler.server.master.cache.ProcessInstanceExecCacheManager;
import org.apache.dolphinscheduler.server.master.command.ICommandFetcher;
import org.apache.dolphinscheduler.server.master.config.MasterConfig;
import org.apache.dolphinscheduler.server.master.config.MasterServerLoadProtection;
import org.apache.dolphinscheduler.server.master.event.WorkflowEvent;
import org.apache.dolphinscheduler.server.master.event.WorkflowEventQueue;
import org.apache.dolphinscheduler.server.master.event.WorkflowEventType;
import org.apache.dolphinscheduler.server.master.exception.WorkflowCreateException;
import org.apache.dolphinscheduler.server.master.metrics.MasterServerMetrics;
import org.apache.dolphinscheduler.service.command.CommandService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
@Slf4j
public class MasterTriggerBootstrap extends BaseDaemonThread implements AutoCloseable {
@Autowired
private ICommandFetcher commandFetcher;
@Autowired
private CommandService commandService;
@Autowired
private MasterConfig masterConfig;
@Autowired
private ProcessInstanceExecCacheManager processInstanceExecCacheManager;
@Autowired
private WorkflowExecuteRunnableFactory workflowExecuteRunnableFactory;
@Autowired
private WorkflowEventQueue workflowEventQueue;
@Autowired
private WorkflowEventLooper workflowEventLooper;
@Autowired
private MasterTaskExecutorBootstrap masterTaskExecutorBootstrap;
@Autowired
private MetricsProvider metricsProvider;
protected MasterTriggerBootstrap() {
super("MasterTriggerBootstrap");
}
@Override
public synchronized void start() {
log.info("MasterTriggerBootstrap starting..");
super.start();
// workflowEventLooper.start();
// masterTaskExecutorBootstrap.start();
log.info("MasterTriggerBootstrap started...");
}
@Override
public void close() throws Exception {
log.info("MasterTriggerBootstrap stopping...");
// try (
// final WorkflowEventLooper workflowEventLooper1 = workflowEventLooper;
// final MasterTaskExecutorBootstrap masterTaskExecutorBootstrap1 = masterTaskExecutorBootstrap) {
// // closed the resource
// }
log.info("MasterTriggerBootstrap stopped...");
}
@Override
public void run() {
MasterServerLoadProtection serverLoadProtection = masterConfig.getServerLoadProtection();
while (!ServerLifeCycleManager.isStopped()) {
try {
if (!ServerLifeCycleManager.isRunning()) {
// the current server is not at running status, cannot consume command.
log.warn("The current server is not at running status, cannot consumes commands.");
Thread.sleep(Constants.SLEEP_TIME_MILLIS);
}
// todo: if the workflow event queue is much, we need to handle the back pressure
SystemMetrics systemMetrics = metricsProvider.getSystemMetrics();
if (serverLoadProtection.isOverload(systemMetrics)) {
log.warn("The current server is overload, cannot consumes commands.");
MasterServerMetrics.incMasterOverload();
Thread.sleep(Constants.SLEEP_TIME_MILLIS);
continue;
}
List<Command> commands = commandFetcher.fetchCommands();
if (CollectionUtils.isEmpty(commands)) {
// indicate that no command ,sleep for 1s
Thread.sleep(Constants.SLEEP_TIME_MILLIS);
continue;
}
//
// commands.parallelStream()
// .forEach(command -> {
// try {
// Optional<WorkflowExecuteRunnable> workflowExecuteRunnableOptional =
// workflowExecuteRunnableFactory.createWorkflowExecuteRunnable(command);
// if (!workflowExecuteRunnableOptional.isPresent()) {
// log.warn(
// "The command execute success, will not trigger a WorkflowExecuteRunnable, this workflowInstance might be in serial mode");
// return;
// }
// WorkflowExecuteRunnable workflowExecuteRunnable = workflowExecuteRunnableOptional.get();
// ProcessInstance processInstance = workflowExecuteRunnable
// .getWorkflowExecuteContext().getWorkflowInstance();
// if (processInstanceExecCacheManager.contains(processInstance.getId())) {
// log.error(
// "The workflow instance is already been cached, this case shouldn't be happened");
// }
// processInstanceExecCacheManager.cache(processInstance.getId(), workflowExecuteRunnable);
// workflowEventQueue.addEvent(
// new WorkflowEvent(WorkflowEventType.START_WORKFLOW, processInstance.getId()));
// } catch (WorkflowCreateException workflowCreateException) {
// log.error("Master handle command {} error ", command.getId(), workflowCreateException);
// commandService.moveToErrorCommand(command, workflowCreateException.toString());
// }
// });
// MasterServerMetrics.incMasterConsumeCommand(commands.size());
} catch (InterruptedException interruptedException) {
log.warn("MasterTriggerBootstrap interrupted, close the loop", interruptedException);
Thread.currentThread().interrupt();
break;
} catch (Exception e) {
log.error("MasterTriggerBootstrap error", e);
// sleep for 1s here to avoid the database down cause the exception boom
ThreadUtils.sleep(Constants.SLEEP_TIME_MILLIS);
}
}
}
}

View File

@ -0,0 +1,139 @@
package org.apache.dolphinscheduler.server.master.runner;
import org.apache.dolphinscheduler.plugin.task.api.*;
import org.apache.dolphinscheduler.plugin.task.api.log.TaskInstanceLogHeader;
import org.apache.dolphinscheduler.plugin.task.api.utils.LogUtils;
import org.apache.dolphinscheduler.plugin.trigger.api.TriggerCallBack;
import lombok.extern.slf4j.Slf4j;
import javax.annotation.Nullable;
@Slf4j
public abstract class TriggerExecuteRunnable implements Runnable {
protected @Nullable AbstractTask task;
protected TriggerExecuteRunnable() {
}
protected void executeTrigger(TriggerCallBack triggerCallBack) {
if (task == null) {
throw new IllegalArgumentException("The task plugin instance is not initialized");
}
// task.handle(taskCallBack);
}
protected void afterExecute() throws TaskException {
// if (task == null) {
// throw new TaskException("The current task instance is null");
// }
// sendAlertIfNeeded();
//
// sendTaskResult();
//
// WorkerTaskExecutorHolder.remove(taskExecutionContext.getTaskInstanceId());
// log.info("Remove the current task execute context from worker cache");
// clearTaskExecPathIfNeeded();
}
protected void afterThrowing(Throwable throwable) throws TaskException {
// if (cancelTask()) {
// log.info("Cancel the task successfully");
// }
// WorkerTaskExecutorHolder.remove(taskExecutionContext.getTaskInstanceId());
// taskExecutionContext.setCurrentExecutionStatus(TaskExecutionStatus.FAILURE);
// taskExecutionContext.setEndTime(System.currentTimeMillis());
// workerMessageSender.sendMessageWithRetry(taskExecutionContext,
// ITaskInstanceExecutionEvent.TaskInstanceExecutionEventType.FINISH);
// log.info("Get a exception when execute the task, will send the task status: {} to master: {}",
// TaskExecutionStatus.FAILURE.name(), taskExecutionContext.getHost());
}
protected boolean cancelTask() {
// cancel the task
if (task == null) {
return true;
}
try {
task.cancel();
// ProcessUtils.cancelApplication(taskExecutionContext);
return true;
} catch (Exception e) {
log.error("Cancel task failed, this will not affect the taskInstance status, but you need to check manual",
e);
return false;
}
}
@Override
public void run() {
try {
TaskInstanceLogHeader.printInitializeTaskContextHeader();
initializeTask();
TaskInstanceLogHeader.printLoadTaskInstancePluginHeader();
beforeExecute();
// TaskCallBack taskCallBack = TaskCallbackImpl.builder()
// .workerMessageSender(workerMessageSender)
// .taskExecutionContext(taskExecutionContext)
// .build();
TaskInstanceLogHeader.printExecuteTaskHeader();
// executeTrigger(taskCallBack);
TaskInstanceLogHeader.printFinalizeTaskHeader();
afterExecute();
closeLogAppender();
} catch (Throwable ex) {
log.error("Task execute failed, due to meet an exception", ex);
afterThrowing(ex);
closeLogAppender();
} finally {
LogUtils.removeWorkflowAndTaskInstanceIdMDC();
LogUtils.removeTaskInstanceLogFullPathMDC();
}
}
protected void initializeTask() {
log.info("Begin to initialize task");
long taskStartTime = System.currentTimeMillis();
// taskExecutionContext.setStartTime(taskStartTime);
log.info("Set task startTime: {}", taskStartTime);
// String taskAppId = String.format("%s_%s", taskExecutionContext.getProcessInstanceId(),
// taskExecutionContext.getTaskInstanceId());
// taskExecutionContext.setTaskAppId(taskAppId);
// log.info("Set task appId: {}", taskAppId);
// log.info("End initialize task {}", JSONUtils.toPrettyJsonString(taskExecutionContext));
}
protected void beforeExecute() {
}
protected void sendAlertIfNeeded() {
}
protected void sendTaskResult() {
}
protected void clearTaskExecPathIfNeeded() {
}
protected void closeLogAppender() {
}
public @Nullable AbstractTask getTask() {
return task;
}
}

View File

@ -0,0 +1,58 @@
package org.apache.dolphinscheduler.server.master.runner;
import org.apache.dolphinscheduler.plugin.task.api.utils.LogUtils;
import org.apache.dolphinscheduler.server.master.cache.ProcessInstanceExecCacheManager;
import org.apache.dolphinscheduler.server.master.config.MasterConfig;
import org.apache.dolphinscheduler.server.master.event.StateEvent;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureCallback;
@Component
@Slf4j
public class TriggerExecuteThreadPool extends ThreadPoolTaskExecutor {
@Autowired
private MasterConfig masterConfig;
@PostConstruct
private void init() {
this.setDaemon(true);
this.setThreadNamePrefix("StreamTaskExecuteThread-");
this.setMaxPoolSize(masterConfig.getExecThreads());
this.setCorePoolSize(masterConfig.getExecThreads());
}
public void executeEvent(final TriggerExecuteRunnable triggerExecuteRunnable) {
// if (!streamTaskExecuteRunnable.isStart() || streamTaskExecuteRunnable.eventSize() == 0) {
// return;
// }
// int taskInstanceId = streamTaskExecuteRunnable.getTaskInstance().getId();
// ListenableFuture<?> future = this.submitListenable(streamTaskExecuteRunnable::handleEvents);
// future.addCallback(new ListenableFutureCallback() {
//
// @Override
// public void onFailure(Throwable ex) {
// LogUtils.setTaskInstanceIdMDC(taskInstanceId);
// log.error("Stream task instance events handle failed", ex);
// LogUtils.removeTaskInstanceIdMDC();
// }
//
// @Override
// public void onSuccess(Object result) {
// LogUtils.setTaskInstanceIdMDC(taskInstanceId);
// log.info("Stream task instance is finished.");
// LogUtils.removeTaskInstanceIdMDC();
// }
// });
}
}

View File

@ -68,18 +68,16 @@ mybatis-plus:
registry:
type: zookeeper
zookeeper:
namespace: dolphinscheduler
connect-string: localhost:2181
retry-policy:
base-sleep-time: 60ms
max-sleep: 300ms
max-retries: 5
session-timeout: 30s
connection-timeout: 9s
block-until-connected: 600ms
digest: ~
type: jdbc
term-refresh-interval: 2s
term-expire-times: 3
hikari-config:
jdbc-url: jdbc:postgresql://localhost:5432/dolphinscheduler
username: root
password: root
maximum-pool-size: 5
connection-timeout: 9000
idle-timeout: 600000
master:
listen-port: 5678

View File

@ -67,12 +67,8 @@
</encoder>
</appender>
<root level="INFO">
<if condition="${DOCKER:-false}">
<then>
<appender-ref ref="STDOUT"/>
</then>
</if>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
<appender-ref ref="TASKLOGFILE"/>
<appender-ref ref="MASTERLOGFILE"/>
</root>

View File

@ -58,6 +58,10 @@
<groupId>org.apache.dolphinscheduler</groupId>
<artifactId>dolphinscheduler-task-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dolphinscheduler</groupId>
<artifactId>dolphinscheduler-trigger-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dolphinscheduler</groupId>

View File

@ -222,6 +222,11 @@
<artifactId>dolphinscheduler-task-remoteshell</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dolphinscheduler</groupId>
<artifactId>dolphinscheduler-task-trigger</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -48,6 +48,11 @@ public abstract class BaseLinuxShellInterceptorBuilder<T extends BaseLinuxShellI
finalScripts.add(shellHeader());
finalScripts.add("BASEDIR=$(cd `dirname $0`; pwd)");
finalScripts.add("cd $BASEDIR");
finalScripts.add("export JAVA_HOME=/usr/local/jdk1.8.0_371");
finalScripts.add("export HADOOP_HOME=/opt/apache/hadoop-3.3.6");
finalScripts.add("export HIVE_HOME=/opt/apache/apache-hive-3.1.3-bin");
finalScripts.add("export SPARK_HOME=/opt/apache/spark-3.5.0-bin-hadoop3");
finalScripts.add("export FLINK_HOME=/opt/apache/flink-1.18.1");
// add system env
finalScripts.addAll(systemEnvScript());
// add custom env

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.dolphinscheduler</groupId>
<artifactId>dolphinscheduler-task-plugin</artifactId>
<version>dev-SNAPSHOT</version>
</parent>
<artifactId>dolphinscheduler-task-trigger</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.apache.dolphinscheduler</groupId>
<artifactId>dolphinscheduler-spi</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.dolphinscheduler</groupId>
<artifactId>dolphinscheduler-task-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.dolphinscheduler</groupId>
<artifactId>dolphinscheduler-common</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,18 @@
package org.apache.dolphinscheduler.plugin.task.trigger;
public class TriggerException extends RuntimeException {
private static final long serialVersionUID = 8155449302457294758L;
public TriggerException() {
super();
}
public TriggerException(String msg, Throwable cause) {
super(msg, cause);
}
public TriggerException(String msg) {
super(msg);
}
}

View File

@ -0,0 +1,45 @@
/*
* 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.plugin.task.trigger;
import org.apache.dolphinscheduler.plugin.task.api.parameters.AbstractParameters;
import org.apache.commons.lang3.StringUtils;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@Setter
@Getter
@NoArgsConstructor
@ToString
public class TriggerParameters extends AbstractParameters {
private String factoryName;
private String resourceGroupName;
private String pipelineName;
private String runId;
@Override
public boolean checkParameters() {
return StringUtils.isNotEmpty(factoryName) && StringUtils.isNotEmpty(resourceGroupName)
&& StringUtils.isNotEmpty(pipelineName);
}
}

View File

@ -0,0 +1,38 @@
/*
* 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.plugin.task.trigger;
public enum TriggerStatus {
Queued,
InProgress,
Succeeded,
Failed,
Canceling,
Cancelled,
;
/**
* Gets the status property: The status of a pipeline run. Possible values: Queued, InProgress, Succeeded, Failed,
* Canceling, Cancelled.
*
* @return the status value.
*/
TriggerStatus() {
}
}

View File

@ -0,0 +1,103 @@
/*
* 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.plugin.task.trigger;
import org.apache.dolphinscheduler.common.utils.JSONUtils;
import org.apache.dolphinscheduler.plugin.task.api.AbstractRemoteTask;
import org.apache.dolphinscheduler.plugin.task.api.TaskConstants;
import org.apache.dolphinscheduler.plugin.task.api.TaskException;
import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContext;
import java.util.Collections;
import java.util.List;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
@Setter
@Getter
@Slf4j
public class TriggerTask extends AbstractRemoteTask {
private final TaskExecutionContext taskExecutionContext;
private TriggerParameters parameters;
public TriggerTask(TaskExecutionContext taskExecutionContext) {
super(taskExecutionContext);
this.taskExecutionContext = taskExecutionContext;
}
@Override
public List<String> getApplicationIds() throws TaskException {
return Collections.emptyList();
}
@Override
public void init() {
parameters = JSONUtils.parseObject(taskExecutionContext.getTaskParams(), TriggerParameters.class);
log.info("Initialize Datafactory task params {}", JSONUtils.toPrettyJsonString(parameters));
}
@Override
public void submitApplication() throws TaskException {
try {
// start task
exitStatusCode = startDatafactoryTask();
setExitStatusCode(exitStatusCode);
} catch (Exception e) {
setExitStatusCode(TaskConstants.EXIT_CODE_FAILURE);
throw new TaskException("data factory start task error", e);
}
// set runId to the appIds if start success
setAppIds(parameters.getRunId());
}
@Override
public void cancelApplication() throws TaskException {
checkApplicationId();
exitStatusCode = TaskConstants.EXIT_CODE_KILL;
}
@Override
public void trackApplicationStatus() throws TaskException {
checkApplicationId();
Boolean isFinishedSuccessfully = false;
if (!isFinishedSuccessfully) {
exitStatusCode = TaskConstants.EXIT_CODE_FAILURE;
} else {
exitStatusCode = TaskConstants.EXIT_CODE_SUCCESS;
}
}
/**
* check datafactory applicationId or get it from appId
*/
private void checkApplicationId() {
}
public int startDatafactoryTask() {
return 0;
}
@Override
public TriggerParameters getParameters() {
return parameters;
}
}

View File

@ -0,0 +1,47 @@
/*
* 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.plugin.task.trigger;
import org.apache.dolphinscheduler.common.utils.JSONUtils;
import org.apache.dolphinscheduler.plugin.task.api.TaskChannel;
import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContext;
import org.apache.dolphinscheduler.plugin.task.api.parameters.AbstractParameters;
import org.apache.dolphinscheduler.plugin.task.api.parameters.ParametersNode;
import org.apache.dolphinscheduler.plugin.task.api.parameters.resource.ResourceParametersHelper;
public class TriggerTaskChannel implements TaskChannel {
@Override
public void cancelApplication(boolean status) {
}
@Override
public TriggerTask createTask(TaskExecutionContext taskRequest) {
return new TriggerTask(taskRequest);
}
@Override
public AbstractParameters parseParameters(ParametersNode parametersNode) {
return JSONUtils.parseObject(parametersNode.getTaskParams(), TriggerParameters.class);
}
@Override
public ResourceParametersHelper getResources(String parameters) {
return null;
}
}

View File

@ -0,0 +1,46 @@
/*
* 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.plugin.task.trigger;
import org.apache.dolphinscheduler.plugin.task.api.TaskChannel;
import org.apache.dolphinscheduler.plugin.task.api.TaskChannelFactory;
import org.apache.dolphinscheduler.spi.params.base.PluginParams;
import java.util.Collections;
import java.util.List;
import com.google.auto.service.AutoService;
@AutoService(TaskChannelFactory.class)
public class TriggerTaskChannelFactory implements TaskChannelFactory {
@Override
public TaskChannel create() {
return new TriggerTaskChannel();
}
@Override
public String getName() {
return "TRIGGER";
}
@Override
public List<PluginParams> getParams() {
return Collections.emptyList();
}
}

View File

@ -0,0 +1,31 @@
/*
* 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.plugin.task.trigger;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
public class TriggerTaskTest {
}

View File

@ -63,6 +63,7 @@
<module>dolphinscheduler-task-linkis</module>
<module>dolphinscheduler-task-datafactory</module>
<module>dolphinscheduler-task-remoteshell</module>
<module>dolphinscheduler-task-trigger</module>
</modules>
<dependencyManagement>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.dolphinscheduler</groupId>
<artifactId>dolphinscheduler-trigger-plugin</artifactId>
<version>dev-SNAPSHOT</version>
</parent>
<artifactId>dolphinscheduler-trigger-all</artifactId>
<dependencies>
<dependency>
<groupId>org.apache.dolphinscheduler</groupId>
<artifactId>dolphinscheduler-trigger-simple</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.dolphinscheduler</groupId>
<artifactId>dolphinscheduler-trigger-plugin</artifactId>
<version>dev-SNAPSHOT</version>
</parent>
<artifactId>dolphinscheduler-trigger-api</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.apache.dolphinscheduler</groupId>
<artifactId>dolphinscheduler-common</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dolphinscheduler</groupId>
<artifactId>dolphinscheduler-spi</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-annotation</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,45 @@
package org.apache.dolphinscheduler.plugin.trigger.api;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.dolphinscheduler.plugin.trigger.api.enums.TriggerExecutionStatus;
import org.apache.dolphinscheduler.plugin.trigger.api.parameters.AbstractParameters;
import java.util.Map;
import java.util.StringJoiner;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j
public abstract class AbstractTrigger {
@Getter
@Setter
protected Map<String, String> taskOutputParams;
/**
* taskExecutionContext
**/
protected TriggerExecutionContext triggerExecutionContext;
protected AbstractTrigger(TriggerExecutionContext triggerExecutionContext) {
this.triggerExecutionContext = triggerExecutionContext;
}
public void init() {
}
public abstract void handle(TriggerCallBack taskCallBack) throws TriggerException;
public abstract void cancel() throws TriggerException;
/**
* get task parameters
*
* @return AbstractParameters
*/
public abstract AbstractParameters getParameters();
}

View File

@ -0,0 +1,4 @@
package org.apache.dolphinscheduler.plugin.trigger.api;
public interface TriggerCallBack {
}

View File

@ -0,0 +1,7 @@
package org.apache.dolphinscheduler.plugin.trigger.api;
public interface TriggerChannel {
void cancelApplication(boolean status);
AbstractTrigger createTrigger(TriggerExecutionContext taskRequest);
}

View File

@ -0,0 +1,32 @@
/*
* 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.plugin.trigger.api;
import org.apache.dolphinscheduler.spi.common.UiChannelFactory;
import org.apache.dolphinscheduler.spi.plugin.PrioritySPI;
import org.apache.dolphinscheduler.spi.plugin.SPIIdentify;
public interface TriggerChannelFactory extends UiChannelFactory, PrioritySPI {
TriggerChannel create();
default SPIIdentify getIdentify() {
return SPIIdentify.builder().name(getName()).build();
}
}

View File

@ -0,0 +1,425 @@
package org.apache.dolphinscheduler.plugin.trigger.api;
import com.google.common.collect.Sets;
import org.apache.dolphinscheduler.common.constants.DateConstants;
import java.time.Duration;
import java.util.Set;
public class TriggerConstants {
private TriggerConstants() {
throw new IllegalStateException("Utility class");
}
public static final String YARN_APPLICATION_REGEX = "application_\\d+_\\d+";
public static final String FLINK_APPLICATION_REGEX = "JobID \\w+";
/**
* exit code kill
*/
public static final int EXIT_CODE_KILL = 137;
public static final String PID = "pid";
/**
* QUESTION ?
*/
public static final String QUESTION = "?";
/**
* comma ,
*/
public static final String COMMA = ",";
/**
* hyphen
*/
public static final String HYPHEN = "-";
/**
* slash /
*/
public static final String SLASH = "/";
/**
* COLON :
*/
public static final String COLON = ":";
/**
* SPACE " "
*/
public static final String SPACE = " ";
/**
* SINGLE_SLASH /
*/
public static final String SINGLE_SLASH = "/";
/**
* DOUBLE_SLASH //
*/
public static final String DOUBLE_SLASH = "//";
/**
* SINGLE_QUOTES "'"
*/
public static final String SINGLE_QUOTES = "'";
/**
* DOUBLE_QUOTES "\""
*/
public static final String DOUBLE_QUOTES = "\"";
/**
* SEMICOLON ;
*/
public static final String SEMICOLON = ";";
/**
* EQUAL SIGN
*/
public static final String EQUAL_SIGN = "=";
/**
* AT SIGN
*/
public static final String AT_SIGN = "@";
/**
* UNDERLINE
*/
public static final String UNDERLINE = "_";
/**
* sleep time
*/
public static final int SLEEP_TIME_MILLIS = 1000;
/**
* exit code failure
*/
public static final int EXIT_CODE_FAILURE = -1;
/**
* exit code success
*/
public static final int EXIT_CODE_SUCCESS = 0;
/**
* running code
*/
public static final int RUNNING_CODE = 1;
public static final String SH = "sh";
/**
* log flush interval?output when reach the interval
*/
public static final int DEFAULT_LOG_FLUSH_INTERVAL = 1000;
/**
* pstree, get pud and sub pid
*/
public static final String PSTREE = "pstree";
public static final String RWXR_XR_X = "rwxr-xr-x";
/**
* date format of yyyyMMddHHmmss
*/
public static final String PARAMETER_FORMAT_TIME = "yyyyMMddHHmmss";
/**
* new
* schedule time
*/
public static final String PARAMETER_SHECDULE_TIME = "schedule.time";
/**
* system date(yyyyMMddHHmmss)
*/
public static final String PARAMETER_DATETIME = DateConstants.PARAMETER_DATETIME;
/**
* system date(yyyymmdd) today
*/
public static final String PARAMETER_CURRENT_DATE = DateConstants.PARAMETER_CURRENT_DATE;
/**
* system date(yyyymmdd) yesterday
*/
public static final String PARAMETER_BUSINESS_DATE = DateConstants.PARAMETER_BUSINESS_DATE;
/**
* the absolute path of current executing task
*/
public static final String PARAMETER_TASK_EXECUTE_PATH = "system.task.execute.path";
/**
* the instance id of current task
*/
public static final String PARAMETER_TASK_INSTANCE_ID = "system.task.instance.id";
/**
* the definition code of current task
*/
public static final String PARAMETER_TASK_DEFINITION_CODE = "system.task.definition.code";
/**
* the definition name of current task
*/
public static final String PARAMETER_TASK_DEFINITION_NAME = "system.task.definition.name";
/**
* the instance id of the workflow to which current task belongs
*/
public static final String PARAMETER_WORKFLOW_INSTANCE_ID = "system.workflow.instance.id";
/**
* the definition code of the workflow to which current task belongs
*/
public static final String PARAMETER_WORKFLOW_DEFINITION_CODE = "system.workflow.definition.code";
/**
* the definition name of the workflow to which current task belongs
*/
public static final String PARAMETER_WORKFLOW_DEFINITION_NAME = "system.workflow.definition.name";
/**
* the code of the project to which current task belongs
*/
public static final String PARAMETER_PROJECT_CODE = "system.project.code";
/**
* the name of the project to which current task belongs
*/
public static final String PARAMETER_PROJECT_NAME = "system.project.name";
/**
* month_begin
*/
public static final String MONTH_BEGIN = "month_begin";
/**
* add_months
*/
public static final String ADD_MONTHS = "add_months";
/**
* month_end
*/
public static final String MONTH_END = "month_end";
/**
* week_begin
*/
public static final String WEEK_BEGIN = "week_begin";
/**
* week_end
*/
public static final String WEEK_END = "week_end";
/**
* this_day
*/
public static final String THIS_DAY = "this_day";
/**
* last_day
*/
public static final String LAST_DAY = "last_day";
/**
* month_first_day
*/
public static final String MONTH_FIRST_DAY = "month_first_day";
/**
* month_last_day
*/
public static final String MONTH_LAST_DAY = "month_last_day";
/**
* week_first_day
*/
public static final String WEEK_FIRST_DAY = "week_first_day";
/**
* week_last_day
*/
public static final String WEEK_LAST_DAY = "week_last_day";
/**
* year_week
*/
public static final String YEAR_WEEK = "year_week";
/**
* timestamp
*/
public static final String TIMESTAMP = "timestamp";
public static final char SUBTRACT_CHAR = '-';
public static final char ADD_CHAR = '+';
public static final char MULTIPLY_CHAR = '*';
public static final char DIVISION_CHAR = '/';
public static final char LEFT_BRACE_CHAR = '(';
public static final char RIGHT_BRACE_CHAR = ')';
public static final String ADD_STRING = "+";
public static final String MULTIPLY_STRING = "*";
public static final String DIVISION_STRING = "/";
public static final String LEFT_BRACE_STRING = "(";
public static final char P = 'P';
public static final char N = 'N';
public static final String SUBTRACT_STRING = "-";
public static final String LOCAL_PARAMS_LIST = "localParamsList";
public static final String TASK_TYPE = "taskType";
public static final String QUEUE = "queue";
/**
* default display rows
*/
public static final int DEFAULT_DISPLAY_ROWS = 10;
/**
* jar
*/
public static final String JAR = "jar";
/**
* hadoop
*/
public static final String HADOOP = "hadoop";
/**
* -D <property>=<value>
*/
public static final String D = "-D";
/**
* datasource encryption salt
*/
public static final String DATASOURCE_ENCRYPTION_SALT_DEFAULT = "!@#$%^&*";
public static final String DATASOURCE_ENCRYPTION_ENABLE = "datasource.encryption.enable";
public static final String DATASOURCE_ENCRYPTION_SALT = "datasource.encryption.salt";
/**
* kerberos
*/
public static final String KERBEROS = "kerberos";
/**
* kerberos expire time
*/
public static final String KERBEROS_EXPIRE_TIME = "kerberos.expire.time";
/**
* java.security.krb5.conf
*/
public static final String JAVA_SECURITY_KRB5_CONF = "java.security.krb5.conf";
/**
* java.security.krb5.conf.path
*/
public static final String JAVA_SECURITY_KRB5_CONF_PATH = "java.security.krb5.conf.path";
/**
* loginUserFromKeytab user
*/
public static final String LOGIN_USER_KEY_TAB_USERNAME = "login.user.keytab.username";
/**
* loginUserFromKeytab path
*/
public static final String LOGIN_USER_KEY_TAB_PATH = "login.user.keytab.path";
/**
* hadoop.security.authentication
*/
public static final String HADOOP_SECURITY_AUTHENTICATION = "hadoop.security.authentication";
/**
* hadoop.security.authentication
*/
public static final String HADOOP_SECURITY_AUTHENTICATION_STARTUP_STATE =
"hadoop.security.authentication.startup.state";
/**
* hdfs/s3 configuration
* resource.storage.upload.base.path
*/
public static final String RESOURCE_UPLOAD_PATH = "resource.storage.upload.base.path";
/**
* data.quality.jar.dir
*/
public static final String DATA_QUALITY_JAR_DIR = "data-quality.jar.dir";
public static final String TASK_TYPE_CONDITIONS = "CONDITIONS";
public static final String TASK_TYPE_SWITCH = "SWITCH";
public static final String TASK_TYPE_SUB_PROCESS = "SUB_PROCESS";
public static final String TASK_TYPE_DYNAMIC = "DYNAMIC";
public static final String TASK_TYPE_DEPENDENT = "DEPENDENT";
public static final String TASK_TYPE_SQL = "SQL";
public static final String TASK_TYPE_DATA_QUALITY = "DATA_QUALITY";
public static final Set<String> TASK_TYPE_SET_K8S = Sets.newHashSet("K8S", "KUBEFLOW");
public static final String TASK_TYPE_BLOCKING = "BLOCKING";
/**
* azure config
*/
public static final String AZURE_CLIENT_ID = "resource.azure.client.id";
public static final String AZURE_CLIENT_SECRET = "resource.azure.client.secret";
public static final String AZURE_ACCESS_SUB_ID = "resource.azure.subId";
public static final String AZURE_SECRET_TENANT_ID = "resource.azure.tenant.id";
public static final String QUERY_INTERVAL = "resource.query.interval";
/**
* aws config
*/
public static final String AWS_ACCESS_KEY_ID = "resource.aws.access.key.id";
public static final String AWS_SECRET_ACCESS_KEY = "resource.aws.secret.access.key";
public static final String AWS_REGION = "resource.aws.region";
/**
* alibaba cloud config
*/
public static final String ALIBABA_CLOUD_ACCESS_KEY_ID = "resource.alibaba.cloud.access.key.id";
public static final String ALIBABA_CLOUD_ACCESS_KEY_SECRET = "resource.alibaba.cloud.access.key.secret";
public static final String ALIBABA_CLOUD_REGION = "resource.alibaba.cloud.region";
/**
* huawei cloud config
*/
public static final String HUAWEI_CLOUD_ACCESS_KEY_ID = "resource.huawei.cloud.access.key.id";
public static final String HUAWEI_CLOUD_ACCESS_KEY_SECRET = "resource.huawei.cloud.access.key.secret";
/**
* use for k8s task
*/
public static final String API_VERSION = "batch/v1";
public static final String RESTART_POLICY = "Never";
public static final String MEMORY = "memory";
public static final String CPU = "cpu";
public static final String LAYER_LABEL = "k8s.cn/layer";
public static final String LAYER_LABEL_VALUE = "batch";
public static final String NAME_LABEL = "k8s.cn/name";
public static final String TASK_INSTANCE_ID = "taskInstanceId";
public static final String MI = "Mi";
public static final int JOB_TTL_SECONDS = 300;
public static final int LOG_LINES = 500;
public static final String NAMESPACE_NAME = "name";
public static final String CLUSTER = "cluster";
/**
* spark / flink on k8s label name
*/
public static final String UNIQUE_LABEL_NAME = "dolphinscheduler-label";
/**
* conda config used by jupyter task plugin
*/
public static final String CONDA_PATH = "conda.path";
// Loop task constants
public static final Duration DEFAULT_LOOP_STATUS_INTERVAL = Duration.ofSeconds(5L);
}

View File

@ -0,0 +1,18 @@
package org.apache.dolphinscheduler.plugin.trigger.api;
public class TriggerException extends RuntimeException {
private static final long serialVersionUID = 8155449302457294758L;
public TriggerException() {
super();
}
public TriggerException(String msg, Throwable cause) {
super(msg, cause);
}
public TriggerException(String msg) {
super(msg);
}
}

View File

@ -0,0 +1,128 @@
package org.apache.dolphinscheduler.plugin.trigger.api;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* to master/worker task transport
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class TriggerExecutionContext implements Serializable {
private static final long serialVersionUID = -1L;
/**
* trigger id
*/
private int triggerInstanceId;
/**
* trigger name
*/
private String triggerName;
/**
* trigger first submit time.
*/
private long firstSubmitTime;
/**
* trigger start time
*/
private long startTime;
/**
* trigger type
*/
private String triggerType;
/**
* trigger json
*/
private String triggerJson;
/**
* processId
*/
private int processId;
/**
* processCode
*/
private Long processDefineCode;
/**
* processVersion
*/
private int processDefineVersion;
/**
* appIds
*/
private String appIds;
/**
* process instance id
*/
private int processInstanceId;
/**
* process instance schedule time
*/
private long scheduleTime;
/**
* process instance global parameters
*/
private String globalParams;
/**
* execute user id
*/
private int executorId;
/**
* command type if complement
*/
private int cmdTypeIfComplement;
/**
* tenant code
*/
private String tenantCode;
/**
* process define id
*/
private int processDefineId;
/**
* project id
*/
private int projectId;
/**
* project code
*/
private long projectCode;
/**
* taskParams
*/
private String taskParams;
/**
* environmentConfig
*/
private String environmentConfig;
}

View File

@ -0,0 +1,86 @@
/*
* 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.plugin.trigger.api;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
import lombok.extern.slf4j.Slf4j;
import org.apache.dolphinscheduler.common.utils.JSONUtils;
import org.apache.dolphinscheduler.plugin.trigger.api.parameters.AbstractParameters;
import org.apache.dolphinscheduler.plugin.trigger.api.parameters.ParametersNode;
import org.apache.dolphinscheduler.spi.plugin.PrioritySPIFactory;
@Slf4j
public class TriggerPluginManager {
private static final Map<String, TriggerChannelFactory> taskChannelFactoryMap = new HashMap<>();
private static final Map<String, TriggerChannel> taskChannelMap = new HashMap<>();
private static final AtomicBoolean loadedFlag = new AtomicBoolean(false);
/**
* Load task plugins from classpath.
*/
public static void loadPlugin() {
if (!loadedFlag.compareAndSet(false, true)) {
log.warn("The trigger plugin has already been loaded");
return;
}
PrioritySPIFactory<TriggerChannelFactory> prioritySPIFactory = new PrioritySPIFactory<>(TriggerChannelFactory.class);
for (Map.Entry<String, TriggerChannelFactory> entry : prioritySPIFactory.getSPIMap().entrySet()) {
String factoryName = entry.getKey();
TriggerChannelFactory factory = entry.getValue();
log.info("Registering trigger plugin: {} - {}", factoryName, factory.getClass().getSimpleName());
taskChannelFactoryMap.put(factoryName, factory);
taskChannelMap.put(factoryName, factory.create());
log.info("Registered trigger plugin: {} - {}", factoryName, factory.getClass().getSimpleName());
}
}
public static Map<String, TriggerChannel> getTaskChannelMap() {
return Collections.unmodifiableMap(taskChannelMap);
}
public static Map<String, TriggerChannelFactory> getTaskChannelFactoryMap() {
return Collections.unmodifiableMap(taskChannelFactoryMap);
}
public static TriggerChannel getTaskChannel(String type) {
return getTaskChannelMap().get(type);
}
public static boolean checkTaskParameters(ParametersNode parametersNode) {
AbstractParameters abstractParameters = getParameters(parametersNode);
return abstractParameters != null;
}
public static AbstractParameters getParameters(ParametersNode parametersNode) {
String taskType = parametersNode.getTaskType();
if (Objects.isNull(taskType)) {
return null;
}
return null;
}
}

View File

@ -0,0 +1,109 @@
package org.apache.dolphinscheduler.plugin.trigger.api.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import java.util.HashMap;
import java.util.Map;
public enum TriggerExecutionStatus {
SUBMITTED_SUCCESS(0, "submit success"),
RUNNING_EXECUTION(1, "running"),
PAUSE(3, "pause"),
STOP(5, "stop"),
FAILURE(6, "failure"),
SUCCESS(7, "success"),
NEED_FAULT_TOLERANCE(8, "need fault tolerance"),
KILL(9, "kill"),
DELAY_EXECUTION(12, "delay execution"),
FORCED_SUCCESS(13, "forced success"),
DISPATCH(17, "dispatch"),
;
private static final Map<Integer, TriggerExecutionStatus> CODE_MAP = new HashMap<>();
static {
for (TriggerExecutionStatus executionStatus : TriggerExecutionStatus.values()) {
CODE_MAP.put(executionStatus.getCode(), executionStatus);
}
}
/**
* Get <code>TaskExecutionStatus</code> by code, if the code is invalidated will throw {@link IllegalArgumentException}.
*/
public static TriggerExecutionStatus of(int code) {
TriggerExecutionStatus taskExecutionStatus = CODE_MAP.get(code);
if (taskExecutionStatus == null) {
throw new IllegalArgumentException(String.format("The task execution status code: %s is invalidated",
code));
}
return taskExecutionStatus;
}
public boolean isRunning() {
return this == RUNNING_EXECUTION;
}
public boolean isSuccess() {
return this == TriggerExecutionStatus.SUCCESS;
}
public boolean isForceSuccess() {
return this == TriggerExecutionStatus.FORCED_SUCCESS;
}
public boolean isKill() {
return this == TriggerExecutionStatus.KILL;
}
public boolean isFailure() {
return this == TriggerExecutionStatus.FAILURE || this == NEED_FAULT_TOLERANCE;
}
public boolean isPause() {
return this == TriggerExecutionStatus.PAUSE;
}
public boolean isStop() {
return this == TriggerExecutionStatus.STOP;
}
public boolean isFinished() {
return isSuccess() || isKill() || isFailure() || isPause() || isStop() || isForceSuccess();
}
public boolean isNeedFaultTolerance() {
return this == NEED_FAULT_TOLERANCE;
}
public boolean shouldFailover() {
return SUBMITTED_SUCCESS == this
|| DISPATCH == this
|| RUNNING_EXECUTION == this
|| DELAY_EXECUTION == this;
}
@EnumValue
private final int code;
private final String desc;
TriggerExecutionStatus(int code, String desc) {
this.code = code;
this.desc = desc;
}
public int getCode() {
return code;
}
public String getDesc() {
return desc;
}
@Override
public String toString() {
return "TaskExecutionStatus{" + "code=" + code + ", desc='" + desc + '\'' + '}';
}
}

View File

@ -0,0 +1,28 @@
package org.apache.dolphinscheduler.plugin.trigger.api.parameters;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.google.common.collect.Lists;
import org.apache.dolphinscheduler.common.utils.JSONUtils;
@Getter
@Slf4j
public class AbstractParameters implements IParameters {
}

View File

@ -0,0 +1,4 @@
package org.apache.dolphinscheduler.plugin.trigger.api.parameters;
public interface IParameters {
}

View File

@ -0,0 +1,95 @@
package org.apache.dolphinscheduler.plugin.trigger.api.parameters;
public class ParametersNode {
private String taskType;
private String taskParams;
private String dependence;
private String switchResult;
public static ParametersNode.ParametersNodeBuilder builder() {
return new ParametersNode.ParametersNodeBuilder();
}
public static class ParametersNodeBuilder {
private String taskType;
private String taskParams;
private String dependence;
private String switchResult;
public ParametersNodeBuilder taskType(String taskType) {
this.taskType = taskType;
return this;
}
public ParametersNodeBuilder taskParams(String taskParams) {
this.taskParams = taskParams;
return this;
}
public ParametersNodeBuilder dependence(String dependence) {
this.dependence = dependence;
return this;
}
public ParametersNodeBuilder switchResult(String switchResult) {
this.switchResult = switchResult;
return this;
}
public ParametersNode build() {
return new ParametersNode(this.taskType, this.taskParams, this.dependence, this.switchResult);
}
}
public ParametersNode() {
}
public ParametersNode(String taskType, String taskParams, String dependence, String switchResult) {
this.taskType = taskType;
this.taskParams = taskParams;
this.dependence = dependence;
this.switchResult = switchResult;
}
public String getTaskType() {
return taskType;
}
public void setTaskType(String taskType) {
this.taskType = taskType;
}
public String getTaskParams() {
return taskParams;
}
public void setTaskParams(String taskParams) {
this.taskParams = taskParams;
}
public String getDependence() {
return dependence;
}
public void setDependence(String dependence) {
this.dependence = dependence;
}
public String getSwitchResult() {
return switchResult;
}
public void setSwitchResult(String switchResult) {
this.switchResult = switchResult;
}
}

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.dolphinscheduler</groupId>
<artifactId>dolphinscheduler-trigger-plugin</artifactId>
<version>dev-SNAPSHOT</version>
</parent>
<artifactId>dolphinscheduler-trigger-simple</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.apache.dolphinscheduler</groupId>
<artifactId>dolphinscheduler-spi</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.dolphinscheduler</groupId>
<artifactId>dolphinscheduler-trigger-api</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,51 @@
package org.apache.dolphinscheduler.plugin.trigger.simple;
import lombok.extern.slf4j.Slf4j;
import org.apache.dolphinscheduler.plugin.trigger.api.AbstractTrigger;
import org.apache.dolphinscheduler.plugin.trigger.api.TriggerCallBack;
import org.apache.dolphinscheduler.plugin.trigger.api.TriggerException;
import org.apache.dolphinscheduler.plugin.trigger.api.TriggerExecutionContext;
import org.apache.dolphinscheduler.plugin.trigger.api.parameters.AbstractParameters;
@Slf4j
public class SimpleTrigger extends AbstractTrigger {
private SimpleTriggerPatameters simpleTriggerPatameters;
private TriggerExecutionContext triggerExecutionContext;
public SimpleTrigger(TriggerExecutionContext triggerExecutionContext) {
super(triggerExecutionContext);
this.triggerExecutionContext = triggerExecutionContext;
}
@Override
public void init() {
}
@SuppressWarnings("unchecked")
@Override
public void handle(TriggerCallBack triggerCallBack) throws TriggerException {
try {
} catch (Exception e) {
log.error("shell task error", e);
throw new TriggerException("Execute shell task error", e);
}
}
@Override
public void cancel() throws TriggerException {
// cancel process
try {
} catch (Exception e) {
throw new TriggerException("cancel application error", e);
}
}
public AbstractParameters getParameters() {
return simpleTriggerPatameters;
}
}

View File

@ -0,0 +1,20 @@
package org.apache.dolphinscheduler.plugin.trigger.simple;
import org.apache.dolphinscheduler.common.utils.JSONUtils;
import org.apache.dolphinscheduler.plugin.trigger.api.TriggerChannel;
import org.apache.dolphinscheduler.plugin.trigger.api.TriggerExecutionContext;
import org.apache.dolphinscheduler.plugin.trigger.api.parameters.AbstractParameters;
import org.apache.dolphinscheduler.plugin.trigger.api.parameters.ParametersNode;
public class SimpleTriggerChannel implements TriggerChannel {
@Override
public void cancelApplication(boolean status) {
}
@Override
public SimpleTrigger createTrigger(TriggerExecutionContext taskRequest) {
return new SimpleTrigger(taskRequest);
}
}

View File

@ -0,0 +1,48 @@
package org.apache.dolphinscheduler.plugin.trigger.simple;
import org.apache.dolphinscheduler.plugin.trigger.api.TriggerChannel;
import org.apache.dolphinscheduler.plugin.trigger.api.TriggerChannelFactory;
import org.apache.dolphinscheduler.spi.params.base.ParamsOptions;
import org.apache.dolphinscheduler.spi.params.base.PluginParams;
import org.apache.dolphinscheduler.spi.params.base.Validate;
import org.apache.dolphinscheduler.spi.params.input.InputParam;
import org.apache.dolphinscheduler.spi.params.radio.RadioParam;
import java.util.ArrayList;
import java.util.List;
import com.google.auto.service.AutoService;
@AutoService(TriggerChannelFactory.class)
public class SimpleTriggerChannelFactory implements TriggerChannelFactory {
@Override
public TriggerChannel create() {
return new SimpleTriggerChannel();
}
@Override
public String getName() {
return "SIMPLE";
}
@Override
public List<PluginParams> getParams() {
List<PluginParams> paramsList = new ArrayList<>();
InputParam nodeName = InputParam.newBuilder("name", "$t('Node name')")
.addValidate(Validate.newBuilder()
.setRequired(true)
.build())
.build();
RadioParam runFlag = RadioParam.newBuilder("runFlag", "RUN_FLAG")
.addParamsOptions(new ParamsOptions("NORMAL", "NORMAL", false))
.addParamsOptions(new ParamsOptions("FORBIDDEN", "FORBIDDEN", false))
.build();
paramsList.add(nodeName);
paramsList.add(runFlag);
return paramsList;
}
}

View File

@ -0,0 +1,11 @@
package org.apache.dolphinscheduler.plugin.trigger.simple;
import lombok.Getter;
import lombok.Setter;
import org.apache.dolphinscheduler.plugin.trigger.api.parameters.AbstractParameters;
@Getter
@Setter
public class SimpleTriggerPatameters extends AbstractParameters {
}

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.dolphinscheduler</groupId>
<artifactId>dolphinscheduler</artifactId>
<version>dev-SNAPSHOT</version>
</parent>
<artifactId>dolphinscheduler-trigger-plugin</artifactId>
<packaging>pom</packaging>
<modules>
<module>dolphinscheduler-trigger-all</module>
<module>dolphinscheduler-trigger-api</module>
<module>dolphinscheduler-trigger-simple</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.dolphinscheduler</groupId>
<artifactId>dolphinscheduler-bom</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>

View File

@ -1,20 +1,4 @@
# 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.
lockfileVersion: 5.4
lockfileVersion: 5.3
specifiers:
'@antv/layout': 0.1.31

View File

@ -36,6 +36,7 @@ const Sidebar = defineComponent({
const defaultExpandedKeys = [
'workflow',
'task',
'trigger',
'udf-manage',
'service-manage',
'statistical-manage',

View File

@ -167,6 +167,23 @@ export function useDataList() {
payload: { projectName: projectName }
}
]
},
{
label: t('menu.trigger'),
key: 'trigger',
icon: renderIcon(SettingOutlined),
children: [
{
label: t('menu.trigger_definition'),
key: `/projects/${projectCode}/trigger/definitions`,
payload: { projectName: projectName }
},
{
label: t('menu.trigger_instance'),
key: `/projects/${projectCode}/trigger/instances`,
payload: { projectName: projectName }
}
]
}
]
},

View File

@ -33,6 +33,9 @@ export default {
task: 'Task',
task_instance: 'Task Instance',
task_definition: 'Task Definition',
trigger: 'Trigger',
trigger_instance: 'Trigger Instance',
trigger_definition: 'Trigger Definition',
file_manage: 'File Manage',
udf_manage: 'UDF Manage',
resource_manage: 'Resource Manage',

View File

@ -76,6 +76,7 @@ export default {
modify_user: 'Modify User',
operation: 'Operation',
edit: 'Edit',
trigger: '触发',
confirm: 'Confirm',
cancel: 'Cancel',
start: 'Start',
@ -323,6 +324,12 @@ export default {
delete_validate_dependent_tasks_desc:
'The downstream dependent tasks exists. You can not delete the task.'
},
trigger: {
trigger: 'Trigger',
create_trigger: 'Create Trigger',
trigger_definition: 'Trigger Definition',
trigger_name: 'Trigger Name'
},
dag: {
create: 'Create Workflow',
search: 'Search',

View File

@ -34,6 +34,9 @@ export default {
task: '任务',
task_instance: '任务实例',
task_definition: '任务定义',
trigger: '触发器',
trigger_instance: '触发器实例',
trigger_definition: '触发器定义',
file_manage: '文件管理',
udf_manage: 'UDF管理',
resource_manage: '资源管理',

View File

@ -76,6 +76,7 @@ export default {
modify_user: '修改用户',
operation: '操作',
edit: '编辑',
trigger: '触发',
confirm: '确定',
cancel: '取消',
start: '运行',
@ -319,6 +320,12 @@ export default {
remove_task_cache: '清除缓存',
delete_validate_dependent_tasks_desc: '下游存在依赖,你不能删除该任务定义'
},
trigger: {
trigger: '触发器',
create_trigger: '创建触发器',
trigger_definition: '触发器定义',
trigger_name: '触发器名称'
},
dag: {
create: '创建工作流',
search: '搜索',

View File

@ -201,6 +201,28 @@ export default {
auth: []
}
},
{
path: '/projects/:projectCode/trigger/definitions',
name: 'trigger-definition',
component: components['projects-trigger-definition'],
meta: {
title: '触发器定义',
activeMenu: 'projects',
showSide: true,
auth: []
}
},
{
path: '/projects/:projectCode/trigger/instances',
name: 'trigger-instance',
component: components['projects-trigger-instance'],
meta: {
title: '触发器实例',
activeMenu: 'projects',
showSide: true,
auth: []
}
},
{
path: '/projects/:projectCode/workflow-definition/tree/:definitionCode',
name: 'workflow-definition-tree',

View File

@ -0,0 +1,172 @@
/*
* 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.
*/
import { axios } from '@/service/service'
import {
PageReq,
ProjectCodeReq,
TaskDefinitionListReq,
TaskDefinitionJsonReq,
CodeReq,
TaskDefinitionJsonObjReq,
ReleaseStateReq,
VersionReq,
ISingleSaveReq,
TaskDefinitionReq
} from './types'
export function queryTriggerDefinitionListPaging(
params: TaskDefinitionListReq,
projectCode: ProjectCodeReq
): any {
return axios({
url: `/projects/${projectCode.projectCode}/task-definition`,
method: 'get',
params
})
}
export function save(
data: TaskDefinitionJsonReq,
projectCode: ProjectCodeReq
): any {
return axios({
url: `/projects/${projectCode}/task-definition`,
method: 'post',
data
})
}
export function genTaskCodeList(num: number, projectCode: number) {
return axios.request<unknown, number[]>({
url: `/projects/${projectCode}/task-definition/gen-task-codes`,
method: 'get',
params: {
genNum: num
}
})
}
export function queryTriggerDefinitionByCode(
code: number,
projectCode: number
): any {
return axios({
url: `/projects/${projectCode}/task-definition/${code}`,
method: 'get'
})
}
export function updateTrigger(
projectCode: number,
code: number,
data: TaskDefinitionJsonObjReq
): any {
return axios({
url: `/projects/${projectCode}/task-definition/${code}`,
method: 'put',
data
})
}
export function deleteTriggerDefinition(
code: CodeReq,
projectCode: ProjectCodeReq
): any {
return axios({
url: `/projects/${projectCode.projectCode}/task-definition/${code.code}`,
method: 'delete'
})
}
export function releaseTaskDefinition(
data: ReleaseStateReq,
code: number,
projectCode: number
): any {
return axios({
url: `/projects/${projectCode}/task-definition/${code}/release`,
method: 'post',
data
})
}
export function queryTaskVersions(
params: PageReq,
code: CodeReq,
projectCode: ProjectCodeReq
): any {
return axios({
url: `/projects/${projectCode.projectCode}/task-definition/${code.code}/versions`,
method: 'get',
params
})
}
export function switchVersion(
version: VersionReq,
code: CodeReq,
projectCode: ProjectCodeReq
): any {
return axios({
url: `/projects/${projectCode.projectCode}/task-definition/${code.code}/versions/${version.version}`,
method: 'get'
})
}
export function deleteVersion(
version: VersionReq,
code: CodeReq,
projectCode: ProjectCodeReq
): any {
return axios({
url: `/projects/${projectCode.projectCode}/task-definition/${code.code}/versions/${version.version}`,
method: 'delete'
})
}
export function saveSingle(projectCode: number, data: ISingleSaveReq) {
return axios({
url: `/projects/${projectCode}/task-definition/save-single`,
method: 'post',
data
})
}
export function updateWithUpstream(
projectCode: number,
code: number,
data: ISingleSaveReq
) {
return axios({
url: `/projects/${projectCode}/task-definition/${code}/with-upstream`,
method: 'put',
data
})
}
export function startTaskDefinition(
projectCode: number,
code: number,
data: TaskDefinitionReq
) {
return axios({
url: `projects/${projectCode}/executors/task-instance/${code}/start`,
method: 'post',
data
})
}

View File

@ -0,0 +1,159 @@
/*
* 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.
*/
interface PageReq {
pageNo: number
pageSize: number
}
interface ListReq extends PageReq {
searchVal?: string
}
interface ProjectCodeReq {
projectCode: number
}
interface TaskDefinitionListReq extends ListReq {
taskType?: string
userId?: number
taskExecuteType?: 'BATCH' | 'STREAM'
}
interface TaskDefinitionJsonReq {
taskDefinitionJson: string
}
interface CodeReq {
code: any
}
interface TaskDefinitionJsonObjReq {
taskDefinitionJsonObj: string
taskExecuteType?: string
}
interface ReleaseStateReq {
releaseState: 'OFFLINE' | 'ONLINE'
}
interface VersionReq {
version: number
}
interface TaskDefinitionItem {
taskName: string
taskCode: any
taskVersion: number
taskType: string
taskCreateTime: string
taskUpdateTime: string
processDefinitionCode: any
processDefinitionVersion: number
processDefinitionName: string
processReleaseState: string
upstreamTaskMap: any
upstreamTaskCode: number
upstreamTaskName: string
}
interface TaskDefinitionRes {
totalList: TaskDefinitionItem[]
total: number
totalPage: number
pageSize: number
currentPage: number
start: number
}
interface TaskDefinitionVersionItem {
id: number
code: number
name: string
version: number
description: string
projectCode: number
userId: number
taskType: string
taskParams: any
taskParamList: any[]
taskParamMap: any
flag: string
taskPriority: string
userName?: any
projectName?: any
workerGroup: string
environmentCode: number
failRetryTimes: number
failRetryInterval: number
timeoutFlag: string
timeoutNotifyStrategy?: any
timeout: number
delayTime: number
resourceIds: string
createTime: string
updateTime: string
modifyBy?: any
taskGroupId: number
taskGroupPriority: number
operator: number
operateTime: string
dependence: string
}
interface TaskDefinitionVersionRes {
totalList: TaskDefinitionVersionItem[]
total: number
totalPage: number
pageSize: number
currentPage: number
start: number
}
interface ISingleSaveReq {
processDefinitionCode?: string
upstreamCodes: string
taskDefinitionJsonObj: string
}
interface TaskDefinitionReq {
version: number
warningType: string
warningGroupId: number
workerGroup?: string
environmentCode?: number
startParams?: string
dryRun?: number
}
export {
PageReq,
ListReq,
ProjectCodeReq,
TaskDefinitionListReq,
TaskDefinitionJsonReq,
CodeReq,
TaskDefinitionJsonObjReq,
ReleaseStateReq,
VersionReq,
TaskDefinitionItem,
TaskDefinitionRes,
TaskDefinitionVersionItem,
TaskDefinitionVersionRes,
ISingleSaveReq,
TaskDefinitionReq
}

View File

@ -60,6 +60,8 @@ type TaskType =
| 'DATA_FACTORY'
| 'REMOTESHELL'
type TriggerType = 'SIMPLE' | 'TIMER' | 'KAFKA'
type ProgramType = 'JAVA' | 'SCALA' | 'PYTHON'
type DependentResultType = {
@ -113,6 +115,7 @@ export {
BDependentResultType,
IMainJar,
TaskType,
TriggerType,
ITaskType,
ITaskTypeItem,
TaskTypeState,

View File

@ -0,0 +1,270 @@
/*
* 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.
*/
import {
defineComponent,
PropType,
ref,
watch,
nextTick,
provide,
computed,
h,
Ref,
onMounted
} from 'vue'
import { useI18n } from 'vue-i18n'
import Modal from '@/components/modal'
import Detail from './detail'
import { formatModel } from './format-data'
import {
HistoryOutlined,
ProfileOutlined,
QuestionCircleTwotone,
BranchesOutlined
} from '@vicons/antd'
import { NIcon } from 'naive-ui'
import { Router, useRouter } from 'vue-router'
import { querySubProcessInstanceByTaskCode } from '@/service/modules/process-instances'
import { useTaskNodeStore } from '@/store/project/task-node'
import type {
ITriggerData,
ITriggerType,
EditWorkflowDefinition,
IWorkflowTaskInstance,
WorkflowInstance
} from './types'
import { queryProjectPreferenceByProjectCode } from '@/service/modules/projects-preference'
import { INodeData } from './types'
const props = {
show: {
type: Boolean as PropType<boolean>,
default: false
},
data: {
type: Object as PropType<ITriggerData>,
default: { code: 0, taskType: 'SHELL', name: '' }
},
projectCode: {
type: Number as PropType<number>,
required: true,
default: 0
},
readonly: {
type: Boolean as PropType<boolean>,
default: false
},
from: {
type: Number as PropType<number>,
default: 0
},
definition: {
type: Object as PropType<Ref<EditWorkflowDefinition>>
},
processInstance: {
type: Object as PropType<WorkflowInstance>
},
taskInstance: {
type: Object as PropType<IWorkflowTaskInstance>
},
saving: {
type: Boolean,
default: false
}
}
const NodeDetailModal = defineComponent({
name: 'NodeDetailModal',
props,
emits: ['cancel', 'submit', 'viewLog'],
setup(props, { emit }) {
const { t, locale } = useI18n()
const router: Router = useRouter()
const taskStore = useTaskNodeStore()
const renderIcon = (icon: any) => {
return () => h(NIcon, null, { default: () => h(icon) })
}
const detailRef = ref()
const onConfirm = async () => {
await detailRef.value.value.validate()
emit('submit', { data: detailRef.value.value.getValues() })
}
const onCancel = () => {
emit('cancel')
}
const headerLinks = ref([] as any)
const projectPreferences = ref({} as any)
const handleViewLog = () => {
if (props.taskInstance) {
emit('viewLog', props.taskInstance.id, props.taskInstance.taskType)
}
}
const initProjectPreferences = (projectCode: number) => {
queryProjectPreferenceByProjectCode(projectCode).then((result: any) => {
if (result?.preferences && result.state === 1) {
projectPreferences.value = JSON.parse(result.preferences)
}
})
}
const restructureNodeData = (data: INodeData) => {
if (!data?.id) {
for (const item in projectPreferences.value) {
if (projectPreferences.value[item] !== null && item in data) {
Object.assign(data, { item: projectPreferences.value[item] })
}
}
}
}
const initHeaderLinks = (processInstance: any, taskType?: ITriggerType) => {
headerLinks.value = [
{
text: t('project.node.instructions'),
show: !!(taskType),
action: () => {
let linkedTaskType = taskType?.toLowerCase().replace('_', '-')
if (taskType === 'PROCEDURE') linkedTaskType = 'stored-procedure'
const helpUrl =
'https://dolphinscheduler.apache.org/' +
locale.value.toLowerCase().replace('_', '-') +
'/docs/latest/user_doc/guide/task/' +
linkedTaskType +
'.html'
window.open(helpUrl)
},
icon: renderIcon(QuestionCircleTwotone)
},
{
text: t('project.node.view_history'),
show: !!props.taskInstance,
action: () => {
router.push({
name: 'task-instance',
query: {
taskCode: props.data.code
}
})
},
icon: renderIcon(HistoryOutlined)
},
{
text: t('project.node.view_log'),
show: !!props.taskInstance,
action: () => {
handleViewLog()
},
icon: renderIcon(ProfileOutlined)
},
{
text: t('project.node.enter_this_child_node'),
show:
props.data.taskType === 'SUB_PROCESS' ||
props.data.taskType === 'DYNAMIC',
disabled:
!props.data.id ||
(router.currentRoute.value.name === 'workflow-instance-detail' &&
!props.taskInstance),
action: () => {
if (router.currentRoute.value.name === 'workflow-instance-detail') {
querySubProcessInstanceByTaskCode(
{ taskId: props.taskInstance?.id },
{ projectCode: props.projectCode }
).then((res: any) => {
router.push({
name: 'workflow-instance-detail',
params: { id: res.subProcessInstanceId },
query: { code: props.data.taskParams?.processDefinitionCode }
})
})
} else {
router.push({
name: 'workflow-definition-detail',
params: { code: props.data.taskParams?.processDefinitionCode }
})
}
},
icon: renderIcon(BranchesOutlined)
}
]
}
const onTaskTypeChange = (taskType: ITriggerType) => {
// eslint-disable-next-line vue/no-mutating-props
props.data.taskType = taskType
initHeaderLinks(props.processInstance, props.data.taskType)
}
provide(
'data',
computed(() => ({
projectCode: props.projectCode,
data: props.data,
from: props.from,
readonly: props.readonly,
definition: props.definition
}))
)
onMounted(() => {
initProjectPreferences(props.projectCode)
})
watch(
() => [props.show, props.data],
async () => {
if (!props.show) return
initHeaderLinks(props.processInstance, props.data.taskType)
taskStore.init()
const nodeData = formatModel(props.data)
await nextTick()
restructureNodeData(nodeData)
detailRef.value.value.setValues(nodeData)
}
)
return () => (
<Modal
show={props.show}
title={
props.from === 1
? `${t('project.task.current_task_settings')}`
: `${t('project.node.current_node_settings')}`
}
onConfirm={onConfirm}
confirmLoading={props.saving}
confirmDisabled={props.readonly}
onCancel={onCancel}
headerLinks={headerLinks}
>
<Detail
ref={detailRef}
onTaskTypeChange={onTaskTypeChange}
key={props.data.triggerType}
/>
</Modal>
)
}
})
export default NodeDetailModal

View File

@ -0,0 +1,84 @@
/*
* 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.
*/
import { defineComponent, ref, watch, inject, Ref, unref } from 'vue'
import Form from '@/components/form'
import { useTask } from './use-task'
import { useTaskNodeStore } from '@/store/project/task-node'
import type { ITaskData, EditWorkflowDefinition } from './types'
interface IDetailPanel {
projectCode: number
data: ITaskData
readonly: false
from: number
detailRef?: Ref
definition?: EditWorkflowDefinition
}
const NodeDetail = defineComponent({
name: 'NodeDetail',
emits: ['taskTypeChange'],
setup(props, { expose, emit }) {
const taskStore = useTaskNodeStore()
const formRef = ref()
const detailData: IDetailPanel = inject('data') || {
projectCode: 0,
data: {
taskType: 'SHELL'
},
readonly: false,
from: 0
}
const { data, projectCode, from, readonly, definition } = unref(detailData)
const { elementsRef, rulesRef, model } = useTask({
data,
projectCode,
from,
readonly,
definition
})
watch(
() => model.taskType,
async (taskType) => {
taskStore.updateName(model.name || '')
emit('taskTypeChange', taskType)
}
)
expose(formRef)
return () => (
<Form
ref={formRef}
meta={{
model,
rules: rulesRef.value,
elements: elementsRef.value,
disabled: unref(readonly)
}}
layout={{
xGap: 10
}}
/>
)
}
})
export default NodeDetail

View File

@ -0,0 +1,93 @@
/*
* 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.
*/
export { useName } from './use-name'
export { useRunFlag } from './use-run-flag'
export { useCache } from './use-cache'
export { useDescription } from './use-description'
export { useTaskPriority } from './use-task-priority'
export { useWorkerGroup } from './use-worker-group'
export { useEnvironmentName } from './use-environment-name'
export { useTaskGroup } from './use-task-group'
export { useFailed } from './use-failed'
export { useResourceLimit } from './use-resource-limit'
export { useDelayTime } from './use-delay-time'
export { useTimeoutAlarm } from './use-timeout-alarm'
export { usePreTasks } from './use-pre-tasks'
export { useTaskType } from './use-task-type'
export { useProcessName } from './use-process-name'
export { useChildNode } from './use-child-node'
export { useTargetTaskName } from './use-target-task-name'
export { useDatasource } from './use-datasource'
export { useSqlType } from './use-sql-type'
export { useProcedure } from './use-procedure'
export { useCustomParams } from './use-custom-params'
export { useCustomLabels } from './use-custom-labels'
export { useNodeSelectors } from './use-node-selectors'
export { useSourceType } from './use-sqoop-source-type'
export { useTargetType } from './use-sqoop-target-type'
export { useRelationCustomParams } from './use-relation-custom-params'
export { useDependentTimeout } from './use-dependent-timeout'
export { useRules } from './use-rules'
export { useDeployMode } from './use-deploy-mode'
export { useDriverCores } from './use-driver-cores'
export { useDriverMemory } from './use-driver-memory'
export { useExecutorNumber } from './use-executor-number'
export { useExecutorMemory } from './use-executor-memory'
export { useExecutorCores } from './use-executor-cores'
export { useMainJar } from './use-main-jar'
export { useResources } from './use-resources'
export { useTaskDefinition } from './use-task-definition'
export { useJavaTaskMainJar } from './use-java-task-main-jar'
export { useShell } from './use-shell'
export { useSpark } from './use-spark'
export { useMr } from './use-mr'
export { useFlink } from './use-flink'
export { useHttp } from './use-http'
export { useSql } from './use-sql'
export { useSqoop } from './use-sqoop'
export { useSeaTunnel } from './use-sea-tunnel'
export { useSwitch } from './use-switch'
export { useDataX } from './use-datax'
export { useConditions } from './use-conditions'
export { useDependent } from './use-dependent'
export { useEmr } from './use-emr'
export { useZeppelin } from './use-zeppelin'
export { useNamespace } from './use-namespace'
export { useK8s } from './use-k8s'
export { useJupyter } from './use-jupyter'
export { useMlflow } from './use-mlflow'
export { useMlflowProjects } from './use-mlflow-projects'
export { useMlflowModels } from './use-mlflow-models'
export { useOpenmldb } from './use-openmldb'
export { useDvc } from './use-dvc'
export { useDinky } from './use-dinky'
export { useSagemaker } from './use-sagemaker'
export { useJava } from './use-java'
export { useChunjun } from './use-chunjun'
export { useChunjunDeployMode } from './use-chunjun-deploy-mode'
export { usePytorch } from './use-pytorch'
export { useHiveCli } from './use-hive-cli'
export { useDms } from './use-dms'
export { useDatasync } from './use-datasync'
export { useKubeflow } from './use-kubeflow'
export { useLinkis } from './use-linkis'
export { useDataFactory } from './use-data-factory'
export { useRemoteShell } from './use-remote-shell'
export { useDynamic } from './use-dynamic'
export { useYarnQueue } from './use-queue'

View File

@ -0,0 +1,29 @@
/*
* 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.
*/
import { useI18n } from 'vue-i18n'
import type { IJsonItem } from '../types'
export function useCache(): IJsonItem {
const { t } = useI18n()
return {
type: 'switch',
field: 'isCache',
name: t('project.node.is_cache'),
span: 12
}
}

View File

@ -0,0 +1,90 @@
/*
* 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.
*/
import { ref, onMounted } from 'vue'
import { useI18n } from 'vue-i18n'
import {
querySimpleList,
queryProcessDefinitionByCode
} from '@/service/modules/process-definition'
import type { IJsonItem } from '../types'
export function useChildNode({
model,
projectCode,
from,
processName,
code
}: {
model: { [field: string]: any }
projectCode: number
from?: number
processName?: number
code?: number
}): IJsonItem {
const { t } = useI18n()
const options = ref([] as { label: string; value: string }[])
const loading = ref(false)
const getProcessList = async () => {
if (loading.value) return
loading.value = true
const res = await querySimpleList(projectCode)
options.value = res
.filter((option: { name: string; code: number }) => option.code !== code)
.map((option: { name: string; code: number }) => ({
label: option.name,
value: option.code
}))
loading.value = false
}
const getProcessListByCode = async (processCode: number) => {
if (!processCode) return
const res = await queryProcessDefinitionByCode(processCode, projectCode)
model.definition = res
}
onMounted(() => {
if (from === 1 && processName) {
getProcessListByCode(processName)
}
getProcessList()
})
return {
type: 'select',
field: 'processDefinitionCode',
span: 24,
name: t('project.node.child_node'),
props: {
loading: loading,
filterable: true
},
options: options,
class: 'select-child-node',
validate: {
trigger: ['input', 'blur'],
required: true,
validator(unuse: any, value: number) {
if (!value) {
return Error(t('project.node.child_node_tips'))
}
}
}
}
}

View File

@ -0,0 +1,49 @@
/*
* 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.
*/
import { useI18n } from 'vue-i18n'
import type { IJsonItem } from '../types'
export function useChunjunDeployMode(span = 24): IJsonItem {
const { t } = useI18n()
return {
type: 'radio',
field: 'deployMode',
name: t('project.node.deploy_mode'),
options: DEPLOY_MODES,
span
}
}
export const DEPLOY_MODES = [
{
label: 'local',
value: 'local'
},
{
label: 'standlone',
value: 'standlone'
},
{
label: 'yarn-session',
value: 'yarn-session'
},
{
label: 'yarn-per-job',
value: 'yarn-per-job'
}
]

View File

@ -0,0 +1,103 @@
/*
* 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.
*/
import { ref, onMounted } from 'vue'
import { useI18n } from 'vue-i18n'
import type { IJsonItem } from '../types'
import { useChunjunDeployMode } from './'
export function useChunjun(model: { [field: string]: any }): IJsonItem[] {
const { t } = useI18n()
const jsonEditorSpan = ref(0)
const customParameterSpan = ref(0)
const initConstants = () => {
jsonEditorSpan.value = 24
customParameterSpan.value = 24
}
onMounted(() => {
initConstants()
})
return [
{
type: 'editor',
field: 'json',
name: t('project.node.chunjun_json_template'),
span: jsonEditorSpan,
validate: {
trigger: ['input', 'trigger'],
required: true,
message: t('project.node.sql_empty_tips')
}
},
{
type: 'custom-parameters',
field: 'localParams',
name: t('project.node.custom_parameters'),
span: customParameterSpan,
children: [
{
type: 'input',
field: 'prop',
span: 10,
props: {
placeholder: t('project.node.prop_tips'),
maxLength: 256
},
validate: {
trigger: ['input', 'blur'],
required: true,
validator(validate: any, value: string) {
if (!value) {
return new Error(t('project.node.prop_tips'))
}
const sameItems = model.localParams.filter(
(item: { prop: string }) => item.prop === value
)
if (sameItems.length > 1) {
return new Error(t('project.node.prop_repeat'))
}
}
}
},
{
type: 'input',
field: 'value',
span: 10,
props: {
placeholder: t('project.node.value_tips'),
maxLength: 256
}
}
]
},
useChunjunDeployMode(24),
{
type: 'input',
field: 'others',
name: t('project.node.option_parameters'),
props: {
type: 'textarea',
placeholder: t('project.node.option_parameters_tips')
}
}
]
}

View File

@ -0,0 +1,127 @@
/*
* 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.
*/
import { useI18n } from 'vue-i18n'
import { useTaskNodeStore } from '@/store/project/task-node'
import { useRelationCustomParams, useTimeoutAlarm } from '.'
import type { IJsonItem } from '../types'
export function useConditions(model: { [field: string]: any }): IJsonItem[] {
const { t } = useI18n()
const taskStore = useTaskNodeStore()
const preTaskOptions = taskStore.preTaskOptions.filter((option) =>
taskStore.preTasks.includes(Number(option.value))
)
const stateOptions = [
{ label: t('project.node.success'), value: 'success' },
{ label: t('project.node.failed'), value: 'failed' }
]
return [
{
type: 'select',
field: 'successNode',
name: t('project.node.state'),
span: 12,
props: {
disabled: true
},
options: stateOptions
},
{
type: 'select',
field: 'successBranch',
name: t('project.node.branch_flow'),
span: 12,
props: {
clearable: true
},
validate: {
trigger: ['input', 'blur'],
validator: (unuse, value) => {
if (value && value === model.failedBranch) {
return new Error(t('project.node.branch_tips'))
}
}
},
options: taskStore.getPostTaskOptions
},
{
type: 'select',
field: 'failedNode',
name: t('project.node.state'),
span: 12,
props: {
disabled: true
},
options: stateOptions
},
{
type: 'select',
field: 'failedBranch',
name: t('project.node.branch_flow'),
span: 12,
props: {
clearable: true
},
validate: {
trigger: ['input', 'blur'],
validator: (unuse, value) => {
if (value && value === model.successBranch) {
return new Error(t('project.node.branch_tips'))
}
}
},
options: taskStore.getPostTaskOptions
},
...useTimeoutAlarm(model),
...useRelationCustomParams({
model,
children: {
type: 'custom-parameters',
field: 'dependItemList',
span: 18,
children: [
{
type: 'select',
field: 'depTaskCode',
span: 10,
options: preTaskOptions
},
{
type: 'select',
field: 'status',
span: 10,
options: [
{
value: 'SUCCESS',
label: t('project.node.success')
},
{
value: 'FAILURE',
label: t('project.node.failed')
}
]
}
]
},
childrenField: 'dependItemList',
name: 'add_pre_task_check_condition'
})
]
}

View File

@ -0,0 +1,82 @@
/*
* 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.
*/
import { Ref } from 'vue'
import { useI18n } from 'vue-i18n'
import type { IJsonItem } from '../types'
export function useCustomLabels({
model,
field,
name = 'custom_labels',
span = 24
}: {
model: { [field: string]: any }
field: string
name?: string
span?: Ref | number
}): IJsonItem[] {
const { t } = useI18n()
return [
{
type: 'custom-parameters',
field: field,
name: t(`project.node.${name}`),
class: 'btn-custom-parameters',
span,
children: [
{
type: 'input',
field: 'label',
span: 8,
class: 'customized-label-name',
props: {
placeholder: t('project.node.label_name_tips'),
maxLength: 256
},
validate: {
trigger: ['input', 'blur'],
required: true,
validator(validate: any, value: string) {
if (!value) {
return new Error(t('project.node.label_name_tips'))
}
const sameItems = model[field].filter(
(item: { label: string }) => item.label === value
)
if (sameItems.length > 1) {
return new Error(t('project.node.label_repeat'))
}
}
}
},
{
type: 'input',
field: 'value',
span: 14,
class: 'customized-label-value',
props: {
placeholder: t('project.node.label_value_tips'),
maxLength: 256
}
}
]
}
]
}

View File

@ -0,0 +1,162 @@
/*
* 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.
*/
import { Ref } from 'vue'
import { useI18n } from 'vue-i18n'
import type { IJsonItem } from '../types'
export function useCustomParams({
model,
field,
isSimple,
name = 'custom_parameters',
span = 24
}: {
model: { [field: string]: any }
field: string
isSimple: boolean
name?: string
span?: Ref | number
}): IJsonItem[] {
const { t } = useI18n()
return [
{
type: 'custom-parameters',
field: field,
name: t(`project.node.${name}`),
class: 'btn-custom-parameters',
span,
children: [
{
type: 'input',
field: 'prop',
span: 6,
class: 'input-param-key',
props: {
placeholder: t('project.node.prop_tips'),
maxLength: 256
},
validate: {
trigger: ['input', 'blur'],
required: true,
validator(validate: any, value: string) {
if (!value) {
return new Error(t('project.node.prop_tips'))
}
const sameItems = model[field].filter(
(item: { prop: string }) => item.prop === value
)
if (sameItems.length > 1) {
return new Error(t('project.node.prop_repeat'))
}
}
}
},
{
type: 'select',
field: 'direct',
span: 4,
options: DIRECT_LIST,
value: 'IN',
props: {
disabled: isSimple
}
},
{
type: 'select',
field: 'type',
span: 6,
options: TYPE_LIST,
value: 'VARCHAR',
props: {
disabled: isSimple
}
},
{
type: 'input',
field: 'value',
span: 6,
class: 'input-param-value',
props: {
placeholder: t('project.node.value_tips'),
maxLength: 256
}
}
]
}
]
}
export const TYPE_LIST = [
{
value: 'VARCHAR',
label: 'VARCHAR'
},
{
value: 'INTEGER',
label: 'INTEGER'
},
{
value: 'LONG',
label: 'LONG'
},
{
value: 'FLOAT',
label: 'FLOAT'
},
{
value: 'DOUBLE',
label: 'DOUBLE'
},
{
value: 'DATE',
label: 'DATE'
},
{
value: 'TIME',
label: 'TIME'
},
{
value: 'TIMESTAMP',
label: 'TIMESTAMP'
},
{
value: 'BOOLEAN',
label: 'BOOLEAN'
},
{
value: 'LIST',
label: 'LIST'
},
{
value: 'FILE',
label: 'FILE'
}
]
export const DIRECT_LIST = [
{
value: 'IN',
label: 'IN'
},
{
value: 'OUT',
label: 'OUT'
}
]

View File

@ -0,0 +1,152 @@
/*
* 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.
*/
import {
queryDataFactoryFactories,
queryDataFactoryPipelines,
queryDataFactoryResourceGroups
} from '@/service/modules/azure'
import { onMounted, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useCustomParams } from '.'
import type { IJsonItem } from '../types'
export function useDataFactory(model: { [field: string]: any }): IJsonItem[] {
const { t } = useI18n()
const factoryLoading = ref(false)
const resourceGroupLoading = ref(false)
const pipelineLoading = ref(false)
const factoryOptions = ref([] as { label: string; value: number }[])
const resourceGroupOptions = ref([] as { label: string; value: number }[])
const pipelineOptions = ref([] as { label: string; value: number }[])
const getFactoryOptions = async () => {
if (factoryLoading.value) return
factoryLoading.value = true
const factories = await queryDataFactoryFactories()
factoryOptions.value = factories.map((factory: string) => ({
label: factory,
value: factory
}))
factoryLoading.value = false
}
const getResourceGroupName = async () => {
if (resourceGroupLoading.value) return
resourceGroupLoading.value = true
const groupNames = await queryDataFactoryResourceGroups()
resourceGroupOptions.value = groupNames.map((groupName: string) => ({
label: groupName,
value: groupName
}))
resourceGroupLoading.value = false
}
const getPipelineName = async (
factoryName: string,
resourceGroupName: string
) => {
if (pipelineLoading.value) return
pipelineLoading.value = true
const pipelineNames = await queryDataFactoryPipelines({
factoryName,
resourceGroupName
})
pipelineOptions.value = pipelineNames.map((pipelineName: string) => ({
label: pipelineName,
value: pipelineName
}))
pipelineLoading.value = false
}
const onChange = () => {
model['pipelineName'] = ''
if (model['factoryName'] && model['resourceGroupName']) {
getPipelineName(model['factoryName'], model['resourceGroupName'])
}
}
watch(
() => model['pipelineName'],
() => {
if (model['pipelineName'] && pipelineOptions.value.length === 0) {
getPipelineName(model['factoryName'], model['resourceGroupName'])
}
}
)
onMounted(() => {
getFactoryOptions()
getResourceGroupName()
})
return [
{
type: 'select',
field: 'factoryName',
span: 24,
name: t('project.node.factory_name'),
options: factoryOptions,
props: {
'on-update:value': onChange,
loading: factoryLoading
},
validate: {
trigger: ['input', 'trigger'],
required: true,
message: t('project.node.factory_tips')
}
},
{
type: 'select',
field: 'resourceGroupName',
span: 24,
name: t('project.node.resource_group_name'),
options: resourceGroupOptions,
props: {
'on-update:value': onChange,
loading: resourceGroupLoading
},
validate: {
trigger: ['input', 'trigger'],
required: true,
message: t('project.node.resource_group_tips')
}
},
{
type: 'select',
field: 'pipelineName',
span: 24,
name: t('project.node.pipeline_name'),
options: pipelineOptions,
props: {
loading: pipelineLoading
},
validate: {
trigger: ['input', 'trigger'],
required: true,
message: t('project.node.pipeline_tips')
}
},
...useCustomParams({
model,
field: 'localParams',
isSimple: true
})
]
}

View File

@ -0,0 +1,238 @@
/*
* 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.
*/
import { ref, onMounted, nextTick, Ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { queryDataSourceList } from '@/service/modules/data-source'
import { indexOf, find } from 'lodash'
import type { IJsonItem } from '../types'
import type { TypeReq } from '@/service/modules/data-source/types'
export function useDatasource(
model: { [field: string]: any },
params: {
supportedDatasourceType?: string[]
typeField?: string
sourceField?: string
span?: Ref | number
testFlag?: Ref | number
} = {}
): IJsonItem[] {
const { t } = useI18n()
const options = ref([] as { label: string; value: string }[])
const datasourceOptions = ref([] as { label: string; value: number }[])
const datasourceTypes = [
{
id: 0,
code: 'MYSQL',
disabled: false
},
{
id: 1,
code: 'POSTGRESQL',
disabled: false
},
{
id: 2,
code: 'HIVE',
disabled: false
},
{
id: 3,
code: 'SPARK',
disabled: false
},
{
id: 4,
code: 'CLICKHOUSE',
disabled: false
},
{
id: 5,
code: 'ORACLE',
disabled: false
},
{
id: 6,
code: 'SQLSERVER',
disabled: false
},
{
id: 7,
code: 'DB2',
disabled: false
},
{
id: 8,
code: 'PRESTO',
disabled: false
},
{
id: 10,
code: 'REDSHIFT',
disabled: false
},
{
id: 11,
code: 'ATHENA',
disabled: false
},
{
id: 12,
code: 'TRINO',
disabled: false
},
{
id: 13,
code: 'STARROCKS',
disabled: false
},
{
id: 14,
code: 'AZURESQL',
disabled: false
},
{
id: 15,
code: 'DAMENG',
disabled: false
},
{
id: 16,
code: 'OCEANBASE',
disabled: false
},
{
id: 17,
code: 'SSH',
disabled: true
},
{
id: 18,
code: 'KYUUBI',
disabled: false
},
{
id: 19,
code: 'DATABEND',
disabled: false
},
{
id: 21,
code: 'VERTICA',
disabled: false
},
{
id: 22,
code: 'HANA',
disabled: false
},
{
id: 23,
code: 'DORIS',
disabled: false
},
{
id: 24,
code: 'ZEPPELIN',
disabled: false
},
{
id: 25,
code: 'SAGEMAKER',
disabled: false
}
]
const getDatasourceTypes = async () => {
options.value = datasourceTypes
.filter((item) => {
if (item.disabled) {
return false
}
if (params.supportedDatasourceType) {
return indexOf(params.supportedDatasourceType, item.code) !== -1
}
return true
})
.map((item) => ({ label: item.code, value: item.code }))
}
const refreshOptions = async () => {
const parameters = {
type: model[params.typeField || 'type'],
testFlag: 0
} as TypeReq
const res = await queryDataSourceList(parameters)
datasourceOptions.value = res.map((item: any) => ({
label: item.name,
value: item.id
}))
const sourceField = params.sourceField || 'datasource'
if (!res.length && model[sourceField]) model[sourceField] = null
if (res.length && model[sourceField]) {
const item = find(res, { id: model[sourceField] })
if (!item) {
model[sourceField] = null
}
}
}
const onChange = () => {
refreshOptions()
}
onMounted(async () => {
getDatasourceTypes()
await nextTick()
refreshOptions()
})
return [
{
type: 'select',
field: params.typeField || 'type',
span: params.span || 12,
name: t('project.node.datasource_type'),
props: {
'on-update:value': onChange
},
options: options,
validate: {
trigger: ['input', 'blur'],
required: true
}
},
{
type: 'select',
field: params.sourceField || 'datasource',
span: params.span || 12,
name: t('project.node.datasource_instances'),
options: datasourceOptions,
validate: {
trigger: ['input', 'blur'],
required: true,
validator(unuse: any, value) {
if (!value && value !== 0) {
return Error(t('project.node.datasource_instances'))
}
}
}
}
]
}

View File

@ -0,0 +1,85 @@
/*
* 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.
*/
import type { IJsonItem } from '../types'
import { watch, ref } from 'vue'
import { useCustomParams } from '.'
export function useDatasync(model: { [field: string]: any }): IJsonItem[] {
const jsonSpan = ref(0)
const destinationLocationArnSpan = ref(0)
const sourceLocationArnSpan = ref(0)
const nameSpan = ref(0)
const cloudWatchLogGroupArnSpan = ref(0)
const resetSpan = () => {
jsonSpan.value = model.jsonFormat ? 24 : 0
destinationLocationArnSpan.value = model.jsonFormat ? 0 : 24
sourceLocationArnSpan.value = model.jsonFormat ? 0 : 24
nameSpan.value = model.jsonFormat ? 0 : 24
cloudWatchLogGroupArnSpan.value = model.jsonFormat ? 0 : 24
}
watch(
() => [model.jsonFormat],
() => {
resetSpan()
}
)
resetSpan()
return [
{
type: 'switch',
field: 'jsonFormat',
name: 'jsonFormat',
span: 12
},
{
type: 'editor',
field: 'json',
name: 'json',
span: jsonSpan
},
{
type: 'input',
field: 'destinationLocationArn',
name: 'destinationLocationArn',
span: destinationLocationArnSpan
},
{
type: 'input',
field: 'sourceLocationArn',
name: 'sourceLocationArn',
span: sourceLocationArnSpan
},
{
type: 'input',
field: 'name',
name: 'name',
span: nameSpan
},
{
type: 'input',
field: 'cloudWatchLogGroupArn',
name: 'cloudWatchLogGroupArn',
span: cloudWatchLogGroupArnSpan
},
...useCustomParams({ model, field: 'localParams', isSimple: false })
]
}

View File

@ -0,0 +1,256 @@
/*
* 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.
*/
import { ref, onMounted, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useCustomParams, useDatasource, useResources } from '.'
import type { IJsonItem } from '../types'
export function useDataX(model: { [field: string]: any }): IJsonItem[] {
const { t } = useI18n()
const jobSpeedByteOptions: any[] = [
{
label: `0(${t('project.node.unlimited')})`,
value: 0
},
{
label: '1KB',
value: 1024
},
{
label: '10KB',
value: 10240
},
{
label: '50KB',
value: 51200
},
{
label: '100KB',
value: 102400
},
{
label: '512KB',
value: 524288
}
]
const jobSpeedRecordOptions: any[] = [
{
label: `0(${t('project.node.unlimited')})`,
value: 0
},
{
label: '500',
value: 500
},
{
label: '1000',
value: 1000
},
{
label: '1500',
value: 1500
},
{
label: '2000',
value: 2000
},
{
label: '2500',
value: 2500
},
{
label: '3000',
value: 3000
}
]
const memoryLimitOptions = [
{
label: '1G',
value: 1
},
{
label: '2G',
value: 2
},
{
label: '3G',
value: 3
},
{
label: '4G',
value: 4
}
]
const sqlEditorSpan = ref(24)
const jsonEditorSpan = ref(0)
const datasourceSpan = ref(12)
const destinationDatasourceSpan = ref(8)
const otherStatementSpan = ref(22)
const jobSpeedSpan = ref(12)
const useResourcesSpan = ref(0)
const initConstants = () => {
if (model.customConfig) {
sqlEditorSpan.value = 0
jsonEditorSpan.value = 24
datasourceSpan.value = 0
destinationDatasourceSpan.value = 0
otherStatementSpan.value = 0
jobSpeedSpan.value = 0
useResourcesSpan.value = 24
} else {
sqlEditorSpan.value = 24
jsonEditorSpan.value = 0
datasourceSpan.value = 12
destinationDatasourceSpan.value = 8
otherStatementSpan.value = 22
jobSpeedSpan.value = 12
useResourcesSpan.value = 0
}
}
const supportedDatasourceType = [
'MYSQL',
'POSTGRESQL',
'ORACLE',
'SQLSERVER',
'CLICKHOUSE',
'DATABEND',
'HIVE',
'PRESTO'
]
onMounted(() => {
initConstants()
})
watch(
() => model.customConfig,
() => {
initConstants()
}
)
return [
{
type: 'switch',
field: 'customConfig',
name: t('project.node.datax_custom_template')
},
...useDatasource(model, {
typeField: 'dsType',
sourceField: 'dataSource',
span: datasourceSpan,
supportedDatasourceType
}),
{
type: 'editor',
field: 'sql',
name: t('project.node.sql_statement'),
span: sqlEditorSpan,
validate: {
trigger: ['input', 'trigger'],
required: true,
message: t('project.node.sql_empty_tips')
}
},
{
type: 'editor',
field: 'json',
name: t('project.node.datax_json_template'),
span: jsonEditorSpan,
validate: {
trigger: ['input', 'trigger'],
required: true,
message: t('project.node.sql_empty_tips')
}
},
useResources(useResourcesSpan),
...useDatasource(model, {
typeField: 'dtType',
sourceField: 'dataTarget',
span: destinationDatasourceSpan,
supportedDatasourceType
}),
{
type: 'input',
field: 'targetTable',
name: t('project.node.datax_target_table'),
span: destinationDatasourceSpan,
props: {
placeholder: t('project.node.datax_target_table_tips')
},
validate: {
trigger: ['input', 'blur'],
required: true
}
},
{
type: 'multi-input',
field: 'preStatements',
name: t('project.node.datax_target_database_pre_sql'),
span: otherStatementSpan,
props: {
placeholder: t('project.node.datax_non_query_sql_tips'),
type: 'textarea',
autosize: { minRows: 1 }
}
},
{
type: 'multi-input',
field: 'postStatements',
name: t('project.node.datax_target_database_post_sql'),
span: otherStatementSpan,
props: {
placeholder: t('project.node.datax_non_query_sql_tips'),
type: 'textarea',
autosize: { minRows: 1 }
}
},
{
type: 'select',
field: 'jobSpeedByte',
name: t('project.node.datax_job_speed_byte'),
span: jobSpeedSpan,
options: jobSpeedByteOptions,
value: 0
},
{
type: 'select',
field: 'jobSpeedRecord',
name: t('project.node.datax_job_speed_record'),
span: jobSpeedSpan,
options: jobSpeedRecordOptions,
value: 1000
},
{
type: 'select',
field: 'xms',
name: t('project.node.datax_job_runtime_memory_xms'),
span: 12,
options: memoryLimitOptions,
value: 1
},
{
type: 'select',
field: 'xmx',
name: t('project.node.datax_job_runtime_memory_xmx'),
span: 12,
options: memoryLimitOptions,
value: 1
},
...useCustomParams({ model, field: 'localParams', isSimple: true })
]
}

View File

@ -0,0 +1,36 @@
/*
* 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.
*/
import { useI18n } from 'vue-i18n'
import type { IJsonItem } from '../types'
export function useDelayTime(model: { [field: string]: any }): IJsonItem {
const { t } = useI18n()
return {
type: 'input-number',
field: 'delayTime',
name: t('project.node.delay_execution_time'),
span: 12,
props: {
min: 0
},
slots: {
suffix: () => t('project.node.minute')
},
value: model.delayTime || 0
}
}

View File

@ -0,0 +1,109 @@
/*
* 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.
*/
import { computed, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import type { IJsonItem } from '../types'
export function useDependentTimeout(model: {
[field: string]: any
}): IJsonItem[] {
const { t } = useI18n()
const timeCompleteSpan = computed(() => (model.timeoutShowFlag ? 24 : 0))
const timeCompleteEnableSpan = computed(() =>
model.timeoutFlag && model.timeoutShowFlag ? 12 : 0
)
const strategyOptions = [
{
label: t('project.node.timeout_alarm'),
value: 'WARN'
},
{
label: t('project.node.timeout_failure'),
value: 'FAILED'
}
]
watch(
() => model.timeoutFlag,
(timeoutFlag) => {
model.timeoutShowFlag = timeoutFlag
}
)
return [
{
type: 'switch',
field: 'timeoutShowFlag',
name: t('project.node.timeout_alarm')
},
{
type: 'switch',
field: 'timeoutFlag',
name: t('project.node.waiting_dependent_complete'),
props: {
'on-update:value': (value: boolean) => {
if (value) {
if (!model.timeoutNotifyStrategy.length) {
model.timeoutNotifyStrategy = ['WARN']
}
if (!model.timeout) {
model.timeout = 30
}
}
}
},
span: timeCompleteSpan
},
{
type: 'input-number',
field: 'timeout',
name: t('project.node.timeout_period'),
span: timeCompleteEnableSpan,
props: {
max: Math.pow(9, 10) - 1
},
slots: {
suffix: () => t('project.node.minute')
},
validate: {
trigger: ['input'],
validator(validate: any, value: number) {
if (model.timeoutFlag && !/^[1-9]\d*$/.test(String(value))) {
return new Error(t('project.node.timeout_period_tips'))
}
}
}
},
{
type: 'checkbox',
field: 'timeoutNotifyStrategy',
name: t('project.node.timeout_strategy'),
options: strategyOptions,
span: timeCompleteEnableSpan,
validate: {
trigger: ['input'],
validator(validate: any, value: []) {
if (model.waitCompleteTimeoutEnable && !value.length) {
return new Error(t('project.node.timeout_strategy_tips'))
}
}
}
}
]
}

View File

@ -0,0 +1,550 @@
/*
* 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.
*/
import { ref, onMounted, watch, h, computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { NEllipsis, NIcon } from 'naive-ui'
import { useRelationCustomParams, useDependentTimeout } from '.'
import { useTaskNodeStore } from '@/store/project/task-node'
import { queryAllProjectListForDependent } from '@/service/modules/projects'
import { tasksState } from '@/common/common'
import {
queryProcessDefinitionList,
getTasksByDefinitionList
} from '@/service/modules/process-definition'
import { Router, useRouter } from 'vue-router'
import type {
IJsonItem,
IDependentItem,
IDependentItemOptions,
IDependTaskOptions,
IDependTask,
ITaskState,
IDateType
} from '../types'
import { IRenderOption } from '../types'
export function useDependent(model: { [field: string]: any }): IJsonItem[] {
const { t } = useI18n()
const router: Router = useRouter()
const nodeStore = useTaskNodeStore()
const dependentFailurePolicyOptions = computed(() => {
return [
{
label: t('project.node.dependent_failure_policy_failure'),
value: 'DEPENDENT_FAILURE_FAILURE'
},
{
label: t('project.node.dependent_failure_policy_waiting'),
value: 'DEPENDENT_FAILURE_WAITING'
}
]
})
const failureWaitingTimeSpan = computed(() =>
model.failurePolicy === 'DEPENDENT_FAILURE_WAITING' ? 12 : 0
)
const dependentResult = nodeStore.getDependentResult
const TasksStateConfig = tasksState(t)
const projectList = ref([] as IRenderOption[])
const processCache = {} as {
[key: number]: IRenderOption[]
}
const taskCache = {} as {
[key: number]: IRenderOption[]
}
const selectOptions = ref([] as IDependTaskOptions[])
const DependentTypeOptions = [
{
value: 'DEPENDENT_ON_WORKFLOW',
label: t('project.node.dependent_on_workflow')
},
{
value: 'DEPENDENT_ON_TASK',
label: t('project.node.dependent_on_task')
}
]
const CYCLE_LIST = [
{
value: 'month',
label: t('project.node.month')
},
{
value: 'week',
label: t('project.node.week')
},
{
value: 'day',
label: t('project.node.day')
},
{
value: 'hour',
label: t('project.node.hour')
}
]
const DATE_LIST = {
hour: [
{
value: 'currentHour',
label: t('project.node.current_hour')
},
{
value: 'last1Hour',
label: t('project.node.last_1_hour')
},
{
value: 'last2Hours',
label: t('project.node.last_2_hour')
},
{
value: 'last3Hours',
label: t('project.node.last_3_hour')
},
{
value: 'last24Hours',
label: t('project.node.last_24_hour')
}
],
day: [
{
value: 'today',
label: t('project.node.today')
},
{
value: 'last1Days',
label: t('project.node.last_1_days')
},
{
value: 'last2Days',
label: t('project.node.last_2_days')
},
{
value: 'last3Days',
label: t('project.node.last_3_days')
},
{
value: 'last7Days',
label: t('project.node.last_7_days')
}
],
week: [
{
value: 'thisWeek',
label: t('project.node.this_week')
},
{
value: 'lastWeek',
label: t('project.node.last_week')
},
{
value: 'lastMonday',
label: t('project.node.last_monday')
},
{
value: 'lastTuesday',
label: t('project.node.last_tuesday')
},
{
value: 'lastWednesday',
label: t('project.node.last_wednesday')
},
{
value: 'lastThursday',
label: t('project.node.last_thursday')
},
{
value: 'lastFriday',
label: t('project.node.last_friday')
},
{
value: 'lastSaturday',
label: t('project.node.last_saturday')
},
{
value: 'lastSunday',
label: t('project.node.last_sunday')
}
],
month: [
{
value: 'thisMonth',
label: t('project.node.this_month')
},
{
value: 'thisMonthBegin',
label: t('project.node.this_month_begin')
},
{
value: 'lastMonth',
label: t('project.node.last_month')
},
{
value: 'lastMonthBegin',
label: t('project.node.last_month_begin')
},
{
value: 'lastMonthEnd',
label: t('project.node.last_month_end')
}
]
} as { [key in IDateType]: { value: string; label: string }[] }
const getProjectList = async () => {
const result = await queryAllProjectListForDependent()
projectList.value = result.map((item: { code: number; name: string }) => ({
value: item.code,
label: () => h(NEllipsis, null, item.name),
filterLabel: item.name
}))
return projectList
}
const getProcessList = async (code: number) => {
if (processCache[code]) {
return processCache[code]
}
const result = await queryProcessDefinitionList(code)
const processList = result.map((item: { code: number; name: string }) => ({
value: item.code,
label: () => h(NEllipsis, null, item.name),
filterLabel: item.name
}))
processCache[code] = processList
return processList
}
const getTaskList = async (code: number, processCode: number) => {
if (taskCache[processCode]) {
return taskCache[processCode]
}
const result = await getTasksByDefinitionList(code, processCode)
const taskList = result.map((item: { code: number; name: string }) => ({
value: item.code,
label: () => h(NEllipsis, null, item.name),
filterLabel: item.name
}))
taskList.unshift({
value: -1,
label: 'ALL',
filterLabel: 'ALL'
})
taskCache[processCode] = taskList
return taskList
}
const renderState = (item: {
definitionCode: number
depTaskCode: number
cycle: string
dateValue: string
}) => {
if (!item || router.currentRoute.value.name !== 'workflow-instance-detail')
return null
const key = `${item.definitionCode}-${item.depTaskCode}-${item.cycle}-${item.dateValue}`
const state: ITaskState = dependentResult[key]
return h(NIcon, { size: 24, color: TasksStateConfig[state]?.color }, () =>
h(TasksStateConfig[state]?.icon)
)
}
onMounted(() => {
getProjectList()
})
watch(
() => model.dependTaskList,
(value) => {
selectOptions.value = []
value.forEach((item: IDependTask, taskIndex: number) => {
if (!item.dependItemList?.length) return
const itemListOptions = ref([] as IDependentItemOptions[])
item.dependItemList?.forEach(
async (dependItem: IDependentItem, itemIndex: number) => {
itemListOptions.value[itemIndex] = {}
if (!dependItem.dependentType) {
if (dependItem.depTaskCode == 0)
dependItem.dependentType = 'DEPENDENT_ON_WORKFLOW'
else dependItem.dependentType = 'DEPENDENT_ON_TASK'
}
if (dependItem.projectCode) {
itemListOptions.value[itemIndex].definitionCodeOptions =
await getProcessList(dependItem.projectCode)
}
if (dependItem.projectCode && dependItem.definitionCode) {
itemListOptions.value[itemIndex].depTaskCodeOptions =
await getTaskList(
dependItem.projectCode,
dependItem.definitionCode
)
}
if (dependItem.cycle) {
itemListOptions.value[itemIndex].dateOptions =
DATE_LIST[dependItem.cycle]
}
}
)
selectOptions.value[taskIndex] = {} as IDependTaskOptions
selectOptions.value[taskIndex].dependItemList = itemListOptions.value
})
}
)
return [
...useDependentTimeout(model),
...useRelationCustomParams({
model,
children: (i = 0) => ({
type: 'custom-parameters',
field: 'dependItemList',
span: 18,
children: [
(j = 0) => ({
type: 'select',
field: 'dependentType',
name: t('project.node.dependent_type'),
span: 24,
props: {
onUpdateValue: (dependentType: string) => {
const item = model.dependTaskList[i].dependItemList[j]
if (item.definitionCode)
item.depTaskCode =
dependentType === 'DEPENDENT_ON_WORKFLOW' ? 0 : -1
}
},
options: DependentTypeOptions,
value: 'DEPENDENT_ON_WORKFLOW'
}),
(j = 0) => ({
type: 'select',
field: 'projectCode',
name: t('project.node.project_name'),
span: 24,
props: {
filterable: true,
filter: (query: string, option: IRenderOption) => {
return option.filterLabel
.toLowerCase()
.includes(query.toLowerCase())
},
onUpdateValue: async (projectCode: number) => {
const item = model.dependTaskList[i].dependItemList[j]
const options = selectOptions?.value[i] || {}
const itemListOptions = options?.dependItemList || []
const itemOptions = {} as IDependentItemOptions
itemOptions.definitionCodeOptions = await getProcessList(
projectCode
)
itemListOptions[j] = itemOptions
options.dependItemList = itemListOptions
selectOptions.value[i] = options
item.depTaskCode = null
item.definitionCode = null
item.parameterPassing = false
}
},
options: projectList,
path: `dependTaskList.${i}.dependItemList.${j}.projectCode`,
rule: {
required: true,
trigger: ['input', 'blur'],
validator(validate: any, value: string) {
if (!value) {
return Error(t('project.node.project_name_tips'))
}
}
}
}),
(j = 0) => ({
type: 'select',
field: 'definitionCode',
span: 24,
name: t('project.node.process_name'),
props: {
filterable: true,
filter: (query: string, option: IRenderOption) => {
return option.filterLabel
.toLowerCase()
.includes(query.toLowerCase())
},
onUpdateValue: async (processCode: number) => {
const item = model.dependTaskList[i].dependItemList[j]
selectOptions.value[i].dependItemList[j].depTaskCodeOptions =
await getTaskList(item.projectCode, processCode)
item.depTaskCode =
item.dependentType === 'DEPENDENT_ON_WORKFLOW' ? 0 : -1
}
},
options:
selectOptions.value[i]?.dependItemList[j]
?.definitionCodeOptions || [],
path: `dependTaskList.${i}.dependItemList.${j}.definitionCode`,
rule: {
required: true,
trigger: ['input', 'blur'],
validator(validate: any, value: string) {
if (!value) {
return Error(t('project.node.process_name_tips'))
}
}
}
}),
(j = 0) => ({
type: 'select',
field: 'depTaskCode',
span: computed(() => {
const item = model.dependTaskList[i].dependItemList[j]
return item.dependentType === 'DEPENDENT_ON_WORKFLOW' ? 0 : 24
}),
name: t('project.node.task_name'),
props: {
filterable: true,
filter: (query: string, option: IRenderOption) => {
return option.filterLabel
.toLowerCase()
.includes(query.toLowerCase())
}
},
options:
selectOptions.value[i]?.dependItemList[j]?.depTaskCodeOptions ||
[],
path: `dependTaskList.${i}.dependItemList.${j}.depTaskCode`,
rule: {
required: true,
trigger: ['input', 'blur'],
validator(validate: any, value: number) {
if (!value && value !== 0) {
return Error(t('project.node.task_name_tips'))
}
}
}
}),
(j = 0) => ({
type: 'select',
field: 'cycle',
span: 10,
name: t('project.node.cycle_time'),
props: {
onUpdateValue: (value: IDateType) => {
selectOptions.value[i].dependItemList[j].dateOptions =
DATE_LIST[value]
model.dependTaskList[i].dependItemList[j].dateValue = null
}
},
options: CYCLE_LIST,
path: `dependTaskList.${i}.dependItemList.${j}.cycle`,
rule: {
required: true,
trigger: ['input', 'blur'],
validator(validate: any, value: string) {
if (!value) {
return Error(t('project.node.cycle_time_tips'))
}
}
}
}),
(j = 0) => ({
type: 'select',
field: 'dateValue',
span: 10,
name: ' ',
options:
selectOptions.value[i]?.dependItemList[j]?.dateOptions || [],
path: `dependTaskList.${i}.dependItemList.${j}.dateValue`,
rule: {
trigger: ['input', 'blur'],
validator(validate: any, value: string) {
if (!value) {
return Error(t('project.node.date_tips'))
}
}
}
}),
(j = 0) => ({
type: 'switch',
field: 'parameterPassing',
span: 20,
name: t('project.node.dependent_task_parameter_passing'),
path: `dependTaskList.${i}.dependItemList.${j}.parameterPassing`
}),
(j = 0) => ({
type: 'custom',
field: 'state',
span: 2,
name: ' ',
widget: renderState(model.dependTaskList[i]?.dependItemList[j])
})
]
}),
childrenField: 'dependItemList',
name: 'add_dependency'
}),
{
type: 'input-number',
field: 'checkInterval',
name: t('project.node.check_interval'),
span: 12,
props: {
max: Math.pow(9, 10) - 1
},
slots: {
suffix: () => t('project.node.second')
},
validate: {
trigger: ['input'],
validator(validate: any, value: number) {
if (!value && !/^[1-9]\d*$/.test(String(value))) {
return new Error(t('project.node.check_interval_tips'))
}
}
}
},
{
type: 'radio',
field: 'failurePolicy',
name: t('project.node.dependent_failure_policy'),
options: dependentFailurePolicyOptions,
span: 24
},
{
type: 'input-number',
field: 'failureWaitingTime',
name: t('project.node.dependent_failure_waiting_time'),
span: failureWaitingTimeSpan,
props: {
max: Math.pow(9, 10) - 1
},
slots: {
suffix: () => t('project.node.minute')
},
validate: {
trigger: ['input'],
required: true,
validator(validate: any, value: number) {
if (model.timeoutFlag && !/^[1-9]\d*$/.test(String(value))) {
return new Error(
t('project.node.dependent_failure_waiting_time_tips')
)
}
}
}
}
]
}

View File

@ -0,0 +1,67 @@
/*
* 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.
*/
import { Ref, ref, watchEffect } from 'vue'
import { useI18n } from 'vue-i18n'
import type { IJsonItem, IOption } from '../types'
export function useDeployMode(
span: number | Ref<number> = 24,
showClient = ref(true),
showCluster = ref(true),
showLocal = ref(true)
): IJsonItem {
const { t } = useI18n()
const deployModeOptions = ref(DEPLOY_MODES as IOption[])
watchEffect(() => {
deployModeOptions.value = DEPLOY_MODES.filter((option) => {
switch (option.value) {
case 'cluster':
return showCluster.value
case 'client':
return showClient.value
case 'local':
return showLocal.value
default:
return true
}
})
})
return {
type: 'radio',
field: 'deployMode',
name: t('project.node.deploy_mode'),
options: deployModeOptions,
span: span
}
}
export const DEPLOY_MODES = [
{
label: 'cluster',
value: 'cluster'
},
{
label: 'client',
value: 'client'
},
{
label: 'local',
value: 'local'
}
]

View File

@ -0,0 +1,33 @@
/*
* 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.
*/
import { useI18n } from 'vue-i18n'
import type { IJsonItem } from '../types'
export function useDescription(): IJsonItem {
const { t } = useI18n()
return {
type: 'input',
field: 'description',
name: t('project.node.description'),
props: {
placeholder: t('project.node.description_tips'),
rows: 2,
type: 'textarea'
}
}
}

View File

@ -0,0 +1,66 @@
/*
* 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.
*/
import { useI18n } from 'vue-i18n'
import { useCustomParams } from '.'
import type { IJsonItem } from '../types'
export function useDinky(model: { [field: string]: any }): IJsonItem[] {
const { t } = useI18n()
return [
{
type: 'input',
field: 'address',
name: t('project.node.dinky_address'),
props: {
placeholder: t('project.node.dinky_address_tips')
},
validate: {
trigger: ['input', 'blur'],
required: true,
validator(_validate: any, value: string) {
if (!value) {
return new Error(t('project.node.dinky_address_tips'))
}
}
}
},
{
type: 'input',
field: 'taskId',
name: t('project.node.dinky_task_id'),
props: {
placeholder: t('project.node.dinky_task_id_tips')
},
validate: {
trigger: ['input', 'blur'],
required: true,
validator(_validate: any, value: string) {
if (!value) {
return new Error(t('project.node.dinky_task_id_tips'))
}
}
}
},
{
type: 'switch',
field: 'online',
name: t('project.node.dinky_online')
},
...useCustomParams({ model, field: 'localParams', isSimple: false })
]
}

View File

@ -0,0 +1,141 @@
/*
* 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.
*/
import type { IJsonItem } from '../types'
import { watch, ref } from 'vue'
import { useCustomParams, useResources } from '.'
export function useDms(model: { [field: string]: any }): IJsonItem[] {
const jsonDataSpan = ref(0)
const replicationTaskArnSpan = ref(0)
const replicationTaskIdentifierSpan = ref(0)
const sourceEndpointArnSpan = ref(0)
const targetEndpointArnSpan = ref(0)
const replicationInstanceArnSpan = ref(0)
const migrationTypeSpan = ref(0)
const tableMappingsSpan = ref(0)
const setFlag = () => {
model.isCreateAndNotJson =
!model.isRestartTask && !model.isJsonFormat ? true : false
model.isRestartAndNotJson =
model.isRestartTask && !model.isJsonFormat ? true : false
}
const resetSpan = () => {
jsonDataSpan.value = model.isJsonFormat ? 24 : 0
replicationTaskArnSpan.value = model.isRestartAndNotJson ? 24 : 0
migrationTypeSpan.value = model.isCreateAndNotJson ? 24 : 0
sourceEndpointArnSpan.value = model.isCreateAndNotJson ? 24 : 0
replicationTaskIdentifierSpan.value = model.isCreateAndNotJson ? 24 : 0
targetEndpointArnSpan.value = model.isCreateAndNotJson ? 24 : 0
replicationInstanceArnSpan.value = model.isCreateAndNotJson ? 24 : 0
tableMappingsSpan.value = model.isCreateAndNotJson ? 24 : 0
}
watch(
() => [model.isRestartTask, model.isJsonFormat],
() => {
setFlag()
resetSpan()
}
)
setFlag()
resetSpan()
return [
{
type: 'switch',
field: 'isRestartTask',
name: 'isRestartTask',
span: 12
},
{
type: 'switch',
field: 'isJsonFormat',
name: 'isJsonFormat',
span: 12
},
{
type: 'editor',
field: 'jsonData',
name: 'jsonData',
span: jsonDataSpan
},
{
type: 'select',
field: 'migrationType',
name: 'migrationType',
span: migrationTypeSpan,
options: MIGRATION_TYPE
},
{
type: 'input',
field: 'replicationTaskIdentifier',
name: 'replicationTaskIdentifier',
span: replicationTaskIdentifierSpan
},
{
type: 'input',
field: 'replicationInstanceArn',
name: 'replicationInstanceArn',
span: replicationInstanceArnSpan
},
{
type: 'input',
field: 'sourceEndpointArn',
name: 'sourceEndpointArn',
span: sourceEndpointArnSpan
},
{
type: 'input',
field: 'targetEndpointArn',
name: 'targetEndpointArn',
span: targetEndpointArnSpan
},
{
type: 'editor',
field: 'tableMappings',
name: 'tableMappings',
span: tableMappingsSpan
},
{
type: 'input',
field: 'replicationTaskArn',
name: 'replicationTaskArn',
span: replicationTaskArnSpan
},
useResources(),
...useCustomParams({ model, field: 'localParams', isSimple: false })
]
}
export const MIGRATION_TYPE = [
{
label: 'full-load',
value: 'full-load'
},
{
label: 'cdc',
value: 'cdc'
},
{
label: 'full-load-and-cdc',
value: 'full-load-and-cdc'
}
]

Some files were not shown because too many files have changed in this diff Show More