From bff0bd9b1d52e5ecaeb45d20469f3c5f5906bf99 Mon Sep 17 00:00:00 2001 From: byteblogs168 <598092184@qq.com> Date: Wed, 13 Dec 2023 16:45:12 +0800 Subject: [PATCH] =?UTF-8?q?feat:=202.6.0=201.=20=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/sql/easy_retry_mysql.sql | 1 + .../datasource/persistence/po/Workflow.java | 20 ++++- .../persistence/po/WorkflowNode.java | 5 ++ .../web/controller/WorkflowController.java | 4 +- .../web/model/request/WorkflowRequestVO.java | 54 ++++++++++--- .../service/convert/WorkflowConverter.java | 25 ++++++ .../web/service/impl/WorkflowServiceImpl.java | 79 ++++++++++++++++++- 7 files changed, 170 insertions(+), 18 deletions(-) create mode 100644 easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/service/convert/WorkflowConverter.java diff --git a/doc/sql/easy_retry_mysql.sql b/doc/sql/easy_retry_mysql.sql index b7e70ffb..c5aa7fc1 100644 --- a/doc/sql/easy_retry_mysql.sql +++ b/doc/sql/easy_retry_mysql.sql @@ -468,6 +468,7 @@ CREATE TABLE `workflow_node` `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', `group_name` varchar(64) NOT NULL COMMENT '组名称', `job_id` bigint(20) NOT NULL COMMENT '任务信息id', + `workflow_id` bigint(20) NOT NULL COMMENT '工作流ID', `node_type` tinyint(4) NOT NULL DEFAULT 1 COMMENT '1、任务节点 2、条件节点', `expression_type` tinyint(4) NOT NULL DEFAULT 0 COMMENT '1、SpEl、2、Aviator 3、QL', `fail_strategy` tinyint(4) NOT NULL DEFAULT 0 COMMENT '失败策略 1、跳过 2、阻塞', diff --git a/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/Workflow.java b/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/Workflow.java index e60bc379..3411f5c3 100644 --- a/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/Workflow.java +++ b/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/Workflow.java @@ -8,6 +8,9 @@ import java.time.LocalDateTime; import lombok.Getter; import lombok.Setter; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + /** *

* 工作流 @@ -40,10 +43,25 @@ public class Workflow implements Serializable { */ private String groupName; + /** + * 触发类型 + */ + private Integer triggerType; + + /** + * 触发间隔 + */ + private String triggerInterval; + + /** + * 执行超时时间 + */ + private Integer executorTimeout; + /** * 工作流状态 0、关闭、1、开启 */ - private Byte workflowStatus; + private Integer workflowStatus; /** * 任务执行时间 diff --git a/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/WorkflowNode.java b/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/WorkflowNode.java index 581281de..235d8163 100644 --- a/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/WorkflowNode.java +++ b/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/WorkflowNode.java @@ -44,6 +44,11 @@ public class WorkflowNode implements Serializable { */ private Long jobId; + /** + * 工作流ID + */ + private Long workflowId; + /** * 1、任务节点 2、条件节点 */ diff --git a/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/controller/WorkflowController.java b/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/controller/WorkflowController.java index 68325704..a35272c3 100644 --- a/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/controller/WorkflowController.java +++ b/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/controller/WorkflowController.java @@ -4,6 +4,7 @@ import com.aizuda.easy.retry.server.web.model.request.WorkflowRequestVO; import com.aizuda.easy.retry.server.web.service.WorkflowService; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; /** @@ -18,9 +19,8 @@ public class WorkflowController { private final WorkflowService workflowService; - @Autowired @PostMapping - public Boolean saveWorkflow(@RequestBody WorkflowRequestVO workflowRequestVO) { + public Boolean saveWorkflow(@RequestBody @Validated WorkflowRequestVO workflowRequestVO) { return workflowService.saveWorkflow(workflowRequestVO); } diff --git a/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/model/request/WorkflowRequestVO.java b/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/model/request/WorkflowRequestVO.java index 582793bd..f769c8d8 100644 --- a/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/model/request/WorkflowRequestVO.java +++ b/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/model/request/WorkflowRequestVO.java @@ -21,7 +21,7 @@ public class WorkflowRequestVO { @Pattern(regexp = "^[A-Za-z0-9_]{1,64}$", message = "仅支持长度为1~64字符且类型为数字、字母和下划线") private String groupName; - @NotBlank(message = "触发类型不能为空") + @NotNull(message = "触发类型不能为空") private Integer triggerType; @NotBlank(message = "触发间隔不能为空") @@ -30,34 +30,62 @@ public class WorkflowRequestVO { @NotNull(message = "执行超时时间不能为空") private Integer executorTimeout; - @NotEmpty(message = "执行超时时间不能为空") - @Valid + /** + * 0、关闭、1、开启 + */ + @NotNull(message = "工作流状态") + private Integer workflowStatus; + + @NotEmpty(message = "节点信息不能为空") private List nodeInfos; @Data public static class NodeInfo { + /** + * 优先级 + */ + private Integer priorityLevel; + + /** + * 1、任务节点 2、条件节点 + */ + @NotNull(message = "节点类型不能为空 ") + private Integer nodeType; + + /** + * 任务ID + */ + @NotNull(message = "任务ID不能为空") + private Long jobId; + + /** + * 表达式类型 1、SpEl、2、Aviator 3、QL + */ + @NotNull(message = "表达式类型不能为空") + private Integer expressionType; + /** * 条件节点表达式 */ private String nodeExpression; - @NotNull(message = "节点类型不能为空") - private Integer nodeType; - - @NotNull(message = "任务ID不能为空") - private Long jobId; - - @NotNull(message = "表达式类型不能为空") - private Integer expressionType; - + /** + * 1、跳过 2、阻塞 + */ @NotNull(message = "失败策略不能为空") private Integer failStrategy; + /** + * 工作流状态 0、关闭、1、开启 + */ + @NotNull(message = "工作流状态不能为空") + private Integer workflowNodeStatus; + /** * 子节点 */ - private List childrenList; + private List childreList; } diff --git a/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/service/convert/WorkflowConverter.java b/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/service/convert/WorkflowConverter.java new file mode 100644 index 00000000..2fe6e2df --- /dev/null +++ b/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/service/convert/WorkflowConverter.java @@ -0,0 +1,25 @@ +package com.aizuda.easy.retry.server.web.service.convert; + +import com.aizuda.easy.retry.server.web.model.request.WorkflowRequestVO; +import com.aizuda.easy.retry.template.datasource.persistence.po.Workflow; +import com.aizuda.easy.retry.template.datasource.persistence.po.WorkflowNode; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * @author: xiaowoniu + * @date : 2023-12-13 + * @since : 2.5.0 + */ +@Mapper +public interface WorkflowConverter { + + WorkflowConverter INSTANCE = Mappers.getMapper(WorkflowConverter.class); + + Workflow toWorkflow(WorkflowRequestVO workflowRequestVO); + + WorkflowNode toWorkflowNode(WorkflowRequestVO.NodeInfo nodeInfo); + +} diff --git a/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/service/impl/WorkflowServiceImpl.java b/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/service/impl/WorkflowServiceImpl.java index 010d4399..e607205a 100644 --- a/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/service/impl/WorkflowServiceImpl.java +++ b/easy-retry-server/easy-retry-server-web/src/main/java/com/aizuda/easy/retry/server/web/service/impl/WorkflowServiceImpl.java @@ -1,8 +1,28 @@ package com.aizuda.easy.retry.server.web.service.impl; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import com.aizuda.easy.retry.common.core.util.JsonUtil; +import com.aizuda.easy.retry.server.common.exception.EasyRetryServerException; import com.aizuda.easy.retry.server.web.model.request.WorkflowRequestVO; +import com.aizuda.easy.retry.server.web.model.request.WorkflowRequestVO.NodeInfo; import com.aizuda.easy.retry.server.web.service.WorkflowService; +import com.aizuda.easy.retry.server.web.service.convert.WorkflowConverter; +import com.aizuda.easy.retry.template.datasource.persistence.mapper.WorkflowMapper; +import com.aizuda.easy.retry.template.datasource.persistence.mapper.WorkflowNodeMapper; +import com.aizuda.easy.retry.template.datasource.persistence.po.Workflow; +import com.aizuda.easy.retry.template.datasource.persistence.po.WorkflowNode; +import com.google.common.collect.Lists; +import com.google.common.graph.GraphBuilder; +import com.google.common.graph.MutableGraph; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * @author xiaowoniu @@ -10,10 +30,65 @@ import org.springframework.stereotype.Service; * @since 2.6.0 */ @Service +@RequiredArgsConstructor public class WorkflowServiceImpl implements WorkflowService { - + private final WorkflowMapper workflowMapper; + private final WorkflowNodeMapper workflowNodeMapper; @Override + @Transactional public boolean saveWorkflow(WorkflowRequestVO workflowRequestVO) { - return false; + + Long root = -1L; + MutableGraph graph = GraphBuilder.directed().build(); + // 添加虚拟头节点 + graph.addNode(root); + + // 组装工作流信息 + Workflow workflow = WorkflowConverter.INSTANCE.toWorkflow(workflowRequestVO); + workflow.setFlowInfo(StrUtil.EMPTY); + Assert.isTrue(1 == workflowMapper.insert(workflow), () -> new EasyRetryServerException("新增工作流失败")); + + // 组装节点信息 + List nodeInfos = workflowRequestVO.getNodeInfos(); + + // 递归构建图 + buildGraph(root, workflowRequestVO.getGroupName(), workflow.getId(), nodeInfos, graph); + + // 保存图信息 + workflow.setFlowInfo(JsonUtil.toJsonString(convertGraphToAdjacencyList(graph))); + workflowMapper.updateById(workflow); + + return true; } + + private Map> convertGraphToAdjacencyList(MutableGraph graph) { + Map> adjacencyList = new HashMap<>(); + + for (Long node : graph.nodes()) { + adjacencyList.put(node, graph.successors(node)); + } + + return adjacencyList; + } + + public void buildGraph(Long parentId, String groupName, Long workflowId, List nodeInfos, MutableGraph graph) { + + if (CollectionUtils.isEmpty(nodeInfos)) { + return; + } + + for (final NodeInfo nodeInfo : nodeInfos) { + WorkflowNode workflowNode = WorkflowConverter.INSTANCE.toWorkflowNode(nodeInfo); + workflowNode.setWorkflowId(workflowId); + workflowNode.setGroupName(groupName); + Assert.isTrue(1 == workflowNodeMapper.insert(workflowNode), () -> new EasyRetryServerException("新增工作流节点失败")); + // 添加节点 + graph.addNode(workflowNode.getId()); + // 添加边 + graph.putEdge(parentId, workflowNode.getId()); + buildGraph(workflowNode.getId(), groupName, workflowId, nodeInfo.getChildreList(), graph); + } + } + + }