From 7bbdeefa9bcd9ad0b158432146de1d60661fa6a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=88=9A=E8=BE=B0=E5=85=88=E7=94=9F?= Date: Sat, 7 Dec 2024 21:01:19 +0800 Subject: [PATCH] 111 --- .../backend/framework/enums/ResponseCode.java | 1 + .../engine/DefaultWorkflowEngine.java | 104 ++++++---- .../workflow/engine/WorkflowEngine.java | 12 ++ .../workflow/entity/WorkflowDefinition.java | 79 +++++++- .../workflow/entity/WorkflowInstance.java | 180 +++++++++++++++++- .../repository/INodeInstanceRepository.java | 5 + .../IWorkflowInstanceRepository.java | 40 +++- .../src/main/resources/messages.properties | 1 + .../main/resources/messages_en_US.properties | 1 + .../main/resources/messages_zh_CN.properties | 1 + .../engine/DefaultWorkflowEngineTest.java | 26 +-- .../WorkflowDefinitionServiceTest.java | 22 +-- 12 files changed, 401 insertions(+), 71 deletions(-) diff --git a/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/ResponseCode.java b/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/ResponseCode.java index 67305dc5..c38e88ec 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/ResponseCode.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/ResponseCode.java @@ -105,6 +105,7 @@ public enum ResponseCode { WORKFLOW_INSTANCE_ALREADY_COMPLETED(2711, "workflow.instance.already.completed"), WORKFLOW_INSTANCE_ALREADY_CANCELED(2712, "workflow.instance.already.canceled"), WORKFLOW_INSTANCE_NOT_RUNNING(2713, "workflow.instance.not.running"), + WORKFLOW_INSTANCE_NOT_PAUSED(2714, "workflow.instance.not.paused"), WORKFLOW_NODE_NOT_FOUND(2720, "workflow.node.not.found"), WORKFLOW_NODE_TYPE_NOT_SUPPORTED(2721, "workflow.node.type.not.supported"), WORKFLOW_NODE_CONFIG_INVALID(2722, "workflow.node.config.invalid"), diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/engine/DefaultWorkflowEngine.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/engine/DefaultWorkflowEngine.java index af03928a..022aae3b 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/engine/DefaultWorkflowEngine.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/engine/DefaultWorkflowEngine.java @@ -60,9 +60,8 @@ public class DefaultWorkflowEngine implements WorkflowEngine { // 2. 创建工作流实例 WorkflowInstance instance = new WorkflowInstance(); instance.setDefinition(definition); - // 设置工作流实例状态 - instance.setStatus(WorkflowInstanceStatusEnum.RUNNING); - instance.setStartTime(LocalDateTime.now()); + // 设置工作流实例初始状态为 PENDING + instance.setStatus(WorkflowInstanceStatusEnum.PENDING); workflowInstanceRepository.save(instance); // 3. 创建工作流上下文 @@ -71,8 +70,10 @@ public class DefaultWorkflowEngine implements WorkflowEngine { variables.forEach((key, value) -> context.setVariable(key, value)); } - // 4. 创建开始节点实例 + // 4. 创建开始节点实例并启动工作流 NodeInstance startNode = createStartNode(definition, instance.getId()); + instance.start(); + workflowInstanceRepository.save(instance); executeNode(startNode.getId()); return instance; @@ -85,8 +86,7 @@ public class DefaultWorkflowEngine implements WorkflowEngine { .orElseThrow(() -> new WorkflowEngineException(ResponseCode.WORKFLOW_NODE_NOT_FOUND)); WorkflowInstance instance = nodeInstance.getWorkflowInstance(); - // 检查工作流实例状态 - if (instance.getStatus() != WorkflowInstanceStatusEnum.RUNNING) { + if (!instance.canExecuteNode()) { throw new WorkflowEngineException(ResponseCode.WORKFLOW_INSTANCE_NOT_RUNNING); } @@ -100,15 +100,32 @@ public class DefaultWorkflowEngine implements WorkflowEngine { // 2. 执行节点 WorkflowContext context = workflowContextFactory.create(instance); executor.execute(nodeInstance, context); + + // 3. 更新节点状态 nodeInstance.setStatus(NodeStatusEnum.COMPLETED); nodeInstance.setEndTime(LocalDateTime.now()); nodeInstanceRepository.save(nodeInstance); + // 4. 检查是否所有节点都已完成 + List uncompletedNodes = nodeInstanceRepository.findByWorkflowInstanceIdAndStatusNot( + instance.getId(), NodeStatusEnum.COMPLETED); + + if (uncompletedNodes.isEmpty()) { + instance.complete(); + workflowInstanceRepository.save(instance); + } + } catch (Exception e) { + // 更新节点状态为失败 nodeInstance.setStatus(NodeStatusEnum.FAILED); nodeInstance.setEndTime(LocalDateTime.now()); nodeInstance.setError(e.getMessage()); nodeInstanceRepository.save(nodeInstance); + + // 更新工作流实例状态 + instance.updateError(e.getMessage()); + workflowInstanceRepository.save(instance); + throw new WorkflowEngineException(ResponseCode.WORKFLOW_NODE_EXECUTION_FAILED, e); } } @@ -142,29 +159,20 @@ public class DefaultWorkflowEngine implements WorkflowEngine { .orElseThrow(() -> new WorkflowEngineException(ResponseCode.WORKFLOW_INSTANCE_NOT_FOUND)); // 检查工作流实例状态 - if (instance.getStatus() != WorkflowInstanceStatusEnum.RUNNING) { + if (!instance.canTerminate()) { throw new WorkflowEngineException(ResponseCode.WORKFLOW_INSTANCE_NOT_RUNNING); } // 终止所有运行中的节点 List runningNodes = nodeInstanceRepository.findByWorkflowInstanceIdAndStatus( instanceId, NodeStatusEnum.RUNNING); - - WorkflowContext context = workflowContextFactory.create(instance); for (NodeInstance node : runningNodes) { - NodeExecutor executor = nodeExecutors.get(node.getNodeType()); - if (executor != null) { - executor.terminate(node, context); - } node.setStatus(NodeStatusEnum.TERMINATED); node.setEndTime(LocalDateTime.now()); nodeInstanceRepository.save(node); } - // 更新工作流实例状态 - instance.setStatus(WorkflowInstanceStatusEnum.TERMINATED); - instance.setEndTime(LocalDateTime.now()); - instance.setError(reason); + instance.terminate(reason); workflowInstanceRepository.save(instance); } @@ -174,22 +182,11 @@ public class DefaultWorkflowEngine implements WorkflowEngine { WorkflowInstance instance = workflowInstanceRepository.findById(instanceId) .orElseThrow(() -> new WorkflowEngineException(ResponseCode.WORKFLOW_INSTANCE_NOT_FOUND)); - // 检查工作流实例状态 - if (instance.getStatus() != WorkflowInstanceStatusEnum.RUNNING) { + if (!instance.canPause()) { throw new WorkflowEngineException(ResponseCode.WORKFLOW_INSTANCE_NOT_RUNNING); } - // 暂停所有运行中的节点 - List runningNodes = nodeInstanceRepository.findByWorkflowInstanceIdAndStatus( - instanceId, NodeStatusEnum.RUNNING); - - for (NodeInstance node : runningNodes) { - node.setStatus(NodeStatusEnum.PAUSED); - nodeInstanceRepository.save(node); - } - - // 更新工作流实例状态 - instance.setStatus(WorkflowInstanceStatusEnum.PAUSED); + instance.pause(); workflowInstanceRepository.save(instance); } @@ -199,24 +196,51 @@ public class DefaultWorkflowEngine implements WorkflowEngine { WorkflowInstance instance = workflowInstanceRepository.findById(instanceId) .orElseThrow(() -> new WorkflowEngineException(ResponseCode.WORKFLOW_INSTANCE_NOT_FOUND)); - // 检查工作流实例状态 - if (instance.getStatus() != WorkflowInstanceStatusEnum.PAUSED) { + if (!instance.canResume()) { + throw new WorkflowEngineException(ResponseCode.WORKFLOW_INSTANCE_NOT_PAUSED); + } + + instance.resume(); + workflowInstanceRepository.save(instance); + } + + @Override + @Transactional + public void retryWorkflow(Long instanceId) { + WorkflowInstance instance = workflowInstanceRepository.findById(instanceId) + .orElseThrow(() -> new WorkflowEngineException(ResponseCode.WORKFLOW_INSTANCE_NOT_FOUND)); + + if (!instance.canRetry()) { throw new WorkflowEngineException(ResponseCode.WORKFLOW_INSTANCE_NOT_RUNNING); } - // 恢复所有暂停的节点 - List pausedNodes = nodeInstanceRepository.findByWorkflowInstanceIdAndStatus( - instanceId, NodeStatusEnum.PAUSED); + // 重试工作流实例 + instance.retry(); + workflowInstanceRepository.save(instance); - for (NodeInstance node : pausedNodes) { - node.setStatus(NodeStatusEnum.RUNNING); + // 获取失败的节点 + List failedNodes = nodeInstanceRepository.findByWorkflowInstanceIdAndStatus( + instanceId, NodeStatusEnum.FAILED); + + // 重试失败的节点 + for (NodeInstance node : failedNodes) { + node.setStatus(NodeStatusEnum.PENDING); + node.setError(null); nodeInstanceRepository.save(node); executeNode(node.getId()); } + } - // 更新工作流实例状态 - instance.setStatus(WorkflowInstanceStatusEnum.RUNNING); - workflowInstanceRepository.save(instance); + @Override + @Transactional + public void checkTimeout(Long instanceId, long timeoutMillis) { + WorkflowInstance instance = workflowInstanceRepository.findById(instanceId) + .orElseThrow(() -> new WorkflowEngineException(ResponseCode.WORKFLOW_INSTANCE_NOT_FOUND)); + + if (instance.isTimeout(timeoutMillis)) { + String error = "Workflow execution timeout after " + timeoutMillis + " milliseconds"; + terminateWorkflow(instanceId, error); + } } private NodeInstance createStartNode(WorkflowDefinition definition, Long instanceId) { diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/engine/WorkflowEngine.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/engine/WorkflowEngine.java index 8e46750e..1dcd8cc9 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/engine/WorkflowEngine.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/engine/WorkflowEngine.java @@ -38,4 +38,16 @@ public interface WorkflowEngine { * 恢复工作流实例 */ void resumeWorkflow(Long instanceId); + + /** + * 重试工作流实例 + */ + void retryWorkflow(Long instanceId); + + /** + * 检查工作流实例是否超时 + * @param instanceId 工作流实例ID + * @param timeoutMillis 超时时间(毫秒) + */ + void checkTimeout(Long instanceId, long timeoutMillis); } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/entity/WorkflowDefinition.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/entity/WorkflowDefinition.java index bad16ddf..441f9047 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/entity/WorkflowDefinition.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/entity/WorkflowDefinition.java @@ -81,10 +81,87 @@ public class WorkflowDefinition extends Entity { @OneToMany(mappedBy = "workflowDefinition", cascade = CascadeType.ALL, orphanRemoval = true) private List nodes = new ArrayList<>(); + /** + * 版本号 + */ + @Column(nullable = false) + private Integer version = 1; + /** * 获取流转配置 */ public String getTransitionConfig() { return transitionConfig; } -} \ No newline at end of file + + /** + * 检查是否可以发布 + */ + public boolean canPublish() { + return status == WorkflowDefinitionStatusEnum.DRAFT; + } + + /** + * 检查是否可以禁用 + */ + public boolean canDisable() { + return status == WorkflowDefinitionStatusEnum.PUBLISHED; + } + + /** + * 检查是否可以启用 + */ + public boolean canEnable() { + return status == WorkflowDefinitionStatusEnum.DISABLED; + } + + /** + * 检查是否可以更新 + */ + public boolean canUpdate() { + return status == WorkflowDefinitionStatusEnum.DRAFT; + } + + /** + * 发布工作流定义 + */ + public void publish() { + if (!canPublish()) { + throw new IllegalStateException("Cannot publish workflow definition in " + status + " status"); + } + this.status = WorkflowDefinitionStatusEnum.PUBLISHED; + } + + /** + * 禁用工作流定义 + */ + public void disable() { + if (!canDisable()) { + throw new IllegalStateException("Cannot disable workflow definition in " + status + " status"); + } + this.status = WorkflowDefinitionStatusEnum.DISABLED; + } + + /** + * 启用工作流定义 + */ + public void enable() { + if (!canEnable()) { + throw new IllegalStateException("Cannot enable workflow definition in " + status + " status"); + } + this.status = WorkflowDefinitionStatusEnum.PUBLISHED; + } + + /** + * 创建新版本 + */ + public WorkflowDefinition createNewVersion() { + WorkflowDefinition newVersion = new WorkflowDefinition(); + newVersion.setCode(this.code); + newVersion.setName(this.name); + newVersion.setDescription(this.description); + newVersion.setVersion(this.version + 1); + newVersion.setStatus(WorkflowDefinitionStatusEnum.DRAFT); + return newVersion; + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/entity/WorkflowInstance.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/entity/WorkflowInstance.java index 2657bd71..3abe893d 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/entity/WorkflowInstance.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/entity/WorkflowInstance.java @@ -25,6 +25,12 @@ public class WorkflowInstance extends Entity { @JoinColumn(name = "workflow_definition_id", nullable = false) private WorkflowDefinition workflowDefinition; + /** + * 工作流定义ID,用于查询优化 + */ + @Column(name = "workflow_definition_id", insertable = false, updatable = false) + private Long workflowDefinitionId; + /** * 项目环境ID */ @@ -68,4 +74,176 @@ public class WorkflowInstance extends Entity { public void setDefinition(WorkflowDefinition definition) { this.workflowDefinition = definition; } -} \ No newline at end of file + + /** + * 检查是否可以启动 + */ + public boolean canStart() { + return status == WorkflowInstanceStatusEnum.CREATED || status == WorkflowInstanceStatusEnum.PENDING; + } + + /** + * 检查是否可以暂停 + */ + public boolean canPause() { + return status == WorkflowInstanceStatusEnum.RUNNING; + } + + /** + * 检查是否可以恢复 + */ + public boolean canResume() { + return status == WorkflowInstanceStatusEnum.PAUSED; + } + + /** + * 检查是否可以终止 + */ + public boolean canTerminate() { + return status == WorkflowInstanceStatusEnum.RUNNING || + status == WorkflowInstanceStatusEnum.PAUSED; + } + + /** + * 检查是否可以完成 + */ + public boolean canComplete() { + return status == WorkflowInstanceStatusEnum.RUNNING; + } + + /** + * 检查是否可以执行节点 + */ + public boolean canExecuteNode() { + return status == WorkflowInstanceStatusEnum.RUNNING; + } + + /** + * 启动工作流实例 + */ + public void start() { + if (!canStart()) { + throw new IllegalStateException("Cannot start workflow instance in " + status + " status"); + } + this.status = WorkflowInstanceStatusEnum.RUNNING; + this.startTime = LocalDateTime.now(); + } + + /** + * 暂停工作流实例 + */ + public void pause() { + if (!canPause()) { + throw new IllegalStateException("Cannot pause workflow instance in " + status + " status"); + } + this.status = WorkflowInstanceStatusEnum.PAUSED; + } + + /** + * 恢复工作流实例 + */ + public void resume() { + if (!canResume()) { + throw new IllegalStateException("Cannot resume workflow instance in " + status + " status"); + } + this.status = WorkflowInstanceStatusEnum.RUNNING; + } + + /** + * 终止工作流实例 + */ + public void terminate(String reason) { + if (!canTerminate()) { + throw new IllegalStateException("Cannot terminate workflow instance in " + status + " status"); + } + this.status = WorkflowInstanceStatusEnum.TERMINATED; + this.endTime = LocalDateTime.now(); + this.error = reason; + } + + /** + * 完成工作流实例 + */ + public void complete() { + if (!canComplete()) { + throw new IllegalStateException("Cannot complete workflow instance in " + status + " status"); + } + this.status = WorkflowInstanceStatusEnum.COMPLETED; + this.endTime = LocalDateTime.now(); + } + + /** + * 标记工作流实例为失败 + */ + public void fail(String error) { + this.status = WorkflowInstanceStatusEnum.FAILED; + this.endTime = LocalDateTime.now(); + this.error = error; + } + + /** + * 检查工作流实例是否处于活动状态 + */ + public boolean isActive() { + return status == WorkflowInstanceStatusEnum.RUNNING || + status == WorkflowInstanceStatusEnum.PENDING || + status == WorkflowInstanceStatusEnum.PAUSED; + } + + /** + * 检查工作流实例是否已经结束 + */ + public boolean isEnded() { + return status == WorkflowInstanceStatusEnum.COMPLETED || + status == WorkflowInstanceStatusEnum.TERMINATED || + status == WorkflowInstanceStatusEnum.FAILED; + } + + /** + * 检查工作流实例是否可以重试 + */ + public boolean canRetry() { + return status == WorkflowInstanceStatusEnum.FAILED; + } + + /** + * 重试工作流实例 + */ + public void retry() { + if (!canRetry()) { + throw new IllegalStateException("Cannot retry workflow instance in " + status + " status"); + } + this.status = WorkflowInstanceStatusEnum.PENDING; + this.error = null; + } + + /** + * 获取工作流实例的运行时长(毫秒) + */ + public long getDuration() { + if (startTime == null) { + return 0; + } + LocalDateTime end = endTime != null ? endTime : LocalDateTime.now(); + return java.time.Duration.between(startTime, end).toMillis(); + } + + /** + * 检查工作流实例是否超时 + * @param timeoutMillis 超时时间(毫秒) + */ + public boolean isTimeout(long timeoutMillis) { + return startTime != null && getDuration() > timeoutMillis; + } + + /** + * 更新工作流实例的错误信息 + */ + public void updateError(String error) { + this.error = error; + if (this.status == WorkflowInstanceStatusEnum.RUNNING) { + this.status = WorkflowInstanceStatusEnum.FAILED; + this.endTime = LocalDateTime.now(); + } + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/repository/INodeInstanceRepository.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/repository/INodeInstanceRepository.java index 53518cfe..ea0ecb2d 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/repository/INodeInstanceRepository.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/repository/INodeInstanceRepository.java @@ -28,4 +28,9 @@ public interface INodeInstanceRepository extends IBaseRepository findByWorkflowInstanceId(Long workflowInstanceId); void deleteByWorkflowInstanceId(Long workflowInstanceId); + + /** + * 查询不是指定状态的节点实例 + */ + List findByWorkflowInstanceIdAndStatusNot(Long workflowInstanceId, NodeStatusEnum status); } \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/repository/IWorkflowInstanceRepository.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/repository/IWorkflowInstanceRepository.java index 2fb225f7..459dd3f7 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/repository/IWorkflowInstanceRepository.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/repository/IWorkflowInstanceRepository.java @@ -7,6 +7,8 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import java.time.LocalDateTime; +import java.util.Collection; import java.util.List; /** @@ -14,20 +16,46 @@ import java.util.List; */ @Repository public interface IWorkflowInstanceRepository extends IBaseRepository { - + /** * 查询指定状态的工作流实例 */ @Query("SELECT i FROM WorkflowInstance i WHERE i.status IN :statuses AND i.deleted = false") List findByStatusIn(@Param("statuses") List statuses); - + /** - * 根据工作流定义ID和状态查询工作流实例数量 + * 根据工作流定义ID和状态查询工作流实例 */ - long countByDefinitionIdAndStatus(Long definitionId, WorkflowInstanceStatusEnum status); - + List findByWorkflowDefinitionIdAndStatus(Long workflowDefinitionId, WorkflowInstanceStatusEnum status); + + /** + * 根据工作流定义ID和状态统计工作流实例数量 + */ + Long countByWorkflowDefinitionIdAndStatus(Long workflowDefinitionId, WorkflowInstanceStatusEnum status); + /** * 查询项目环境的工作流实例 */ List findByProjectEnvIdAndDeletedFalseOrderByCreateTimeDesc(Long projectEnvId); -} \ No newline at end of file + + /** + * 查找超过指定时间未完成的工作流实例 + */ + @Query("SELECT wi FROM WorkflowInstance wi WHERE wi.status = :status AND wi.startTime < :beforeTime") + List findTimeoutInstances(@Param("status") WorkflowInstanceStatusEnum status, + @Param("beforeTime") LocalDateTime beforeTime); + + /** + * 查找指定工作流定义下所有未结束的实例 + */ + @Query("SELECT wi FROM WorkflowInstance wi WHERE wi.workflowDefinitionId = :definitionId AND wi.status IN :activeStatuses") + List findActiveInstancesByDefinitionId(@Param("definitionId") Long definitionId, + @Param("activeStatuses") Collection activeStatuses); + + /** + * 统计指定工作流定义下所有未结束的实例数量 + */ + @Query("SELECT COUNT(wi) FROM WorkflowInstance wi WHERE wi.workflowDefinitionId = :definitionId AND wi.status IN :activeStatuses") + Long countActiveInstancesByDefinitionId(@Param("definitionId") Long definitionId, + @Param("activeStatuses") Collection activeStatuses); +} \ No newline at end of file diff --git a/backend/src/main/resources/messages.properties b/backend/src/main/resources/messages.properties index 2c3619f0..a0f7a532 100644 --- a/backend/src/main/resources/messages.properties +++ b/backend/src/main/resources/messages.properties @@ -204,6 +204,7 @@ workflow.instance.not.found=工作流实例不存在 workflow.instance.already.completed=工作流实例已完成 workflow.instance.already.canceled=工作流实例已取消 workflow.instance.not.running=工作流实例未运行 +workflow.instance.not.paused=工作流实例不是暂停状态 workflow.node.not.found=工作流节点不存在 workflow.node.type.not.supported=不支持的节点类型 diff --git a/backend/src/main/resources/messages_en_US.properties b/backend/src/main/resources/messages_en_US.properties index 47c11d16..b0e896f6 100644 --- a/backend/src/main/resources/messages_en_US.properties +++ b/backend/src/main/resources/messages_en_US.properties @@ -24,6 +24,7 @@ workflow.instance.not.found=Workflow instance not found workflow.instance.already.completed=Workflow instance already completed workflow.instance.already.canceled=Workflow instance already canceled workflow.instance.not.running=Workflow instance is not running +workflow.instance.not.paused=Workflow instance is not paused workflow.node.not.found=Workflow node not found workflow.node.type.not.supported=Unsupported node type diff --git a/backend/src/main/resources/messages_zh_CN.properties b/backend/src/main/resources/messages_zh_CN.properties index c36fdd5d..0fd63599 100644 --- a/backend/src/main/resources/messages_zh_CN.properties +++ b/backend/src/main/resources/messages_zh_CN.properties @@ -113,6 +113,7 @@ workflow.instance.not.found=工作流实例不存在 workflow.instance.already.completed=工作流实例已完成 workflow.instance.already.canceled=工作流实例已取消 workflow.instance.not.running=工作流实例未运行 +workflow.instance.not.paused=工作流实例未暂停 workflow.node.not.found=工作流节点不存在 workflow.node.type.not.supported=不支持的节点类型 diff --git a/backend/src/test/java/com/qqchen/deploy/backend/workflow/engine/DefaultWorkflowEngineTest.java b/backend/src/test/java/com/qqchen/deploy/backend/workflow/engine/DefaultWorkflowEngineTest.java index 0efe1f9a..9a089728 100644 --- a/backend/src/test/java/com/qqchen/deploy/backend/workflow/engine/DefaultWorkflowEngineTest.java +++ b/backend/src/test/java/com/qqchen/deploy/backend/workflow/engine/DefaultWorkflowEngineTest.java @@ -10,7 +10,8 @@ import com.qqchen.deploy.backend.workflow.entity.WorkflowDefinition; import com.qqchen.deploy.backend.workflow.entity.WorkflowInstance; import com.qqchen.deploy.backend.workflow.enums.NodeStatusEnum; import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnum; -import com.qqchen.deploy.backend.workflow.enums.WorkflowStatusEnum; +import com.qqchen.deploy.backend.workflow.enums.WorkflowDefinitionStatusEnum; +import com.qqchen.deploy.backend.workflow.enums.WorkflowInstanceStatusEnum; import com.qqchen.deploy.backend.workflow.repository.INodeInstanceRepository; import com.qqchen.deploy.backend.workflow.repository.IWorkflowDefinitionRepository; import com.qqchen.deploy.backend.workflow.repository.IWorkflowInstanceRepository; @@ -79,8 +80,9 @@ class DefaultWorkflowEngineTest { variables.put("key1", "value1"); WorkflowDefinition definition = new WorkflowDefinition(); + definition.setId(1L); definition.setCode(workflowCode); - definition.setStatus(WorkflowStatusEnum.PUBLISHED); + definition.setStatus(WorkflowDefinitionStatusEnum.PUBLISHED); NodeInstance startNode = new NodeInstance(); startNode.setId(1L); @@ -99,7 +101,7 @@ class DefaultWorkflowEngineTest { // 验证结果 assertNotNull(result); - assertEquals(WorkflowStatusEnum.RUNNING, result.getStatus()); + assertEquals(WorkflowInstanceStatusEnum.RUNNING, result.getStatus()); assertNotNull(result.getStartTime()); verify(workflowDefinitionRepository).findByCodeAndDeletedFalse(workflowCode); @@ -129,7 +131,7 @@ class DefaultWorkflowEngineTest { String workflowCode = "draft-workflow"; WorkflowDefinition definition = new WorkflowDefinition(); definition.setCode(workflowCode); - definition.setStatus(WorkflowStatusEnum.DRAFT); + definition.setStatus(WorkflowDefinitionStatusEnum.DRAFT); // 配置Mock行为 when(workflowDefinitionRepository.findByCodeAndDeletedFalse(workflowCode)).thenReturn(definition); @@ -150,7 +152,7 @@ class DefaultWorkflowEngineTest { nodeInstance.setStatus(NodeStatusEnum.PENDING); WorkflowInstance instance = new WorkflowInstance(); - instance.setStatus(WorkflowStatusEnum.RUNNING); + instance.setStatus(WorkflowInstanceStatusEnum.RUNNING); nodeInstance.setWorkflowInstance(instance); // 配置Mock行为 @@ -192,7 +194,7 @@ class DefaultWorkflowEngineTest { nodeInstance.setNodeType(NodeTypeEnum.TASK); WorkflowInstance instance = new WorkflowInstance(); - instance.setStatus(WorkflowStatusEnum.COMPLETED); + instance.setStatus(WorkflowInstanceStatusEnum.COMPLETED); nodeInstance.setWorkflowInstance(instance); // 配置Mock行为 @@ -212,7 +214,7 @@ class DefaultWorkflowEngineTest { WorkflowInstance instance = new WorkflowInstance(); instance.setId(instanceId); - instance.setStatus(WorkflowStatusEnum.RUNNING); + instance.setStatus(WorkflowInstanceStatusEnum.RUNNING); NodeInstance runningNode = new NodeInstance(); runningNode.setNodeType(NodeTypeEnum.TASK); @@ -228,7 +230,7 @@ class DefaultWorkflowEngineTest { workflowEngine.terminateWorkflow(instanceId, reason); // 验证结果 - assertEquals(WorkflowStatusEnum.TERMINATED, instance.getStatus()); + assertEquals(WorkflowInstanceStatusEnum.TERMINATED, instance.getStatus()); assertEquals(reason, instance.getError()); assertNotNull(instance.getEndTime()); assertEquals(NodeStatusEnum.TERMINATED, runningNode.getStatus()); @@ -247,7 +249,7 @@ class DefaultWorkflowEngineTest { Long instanceId = 1L; WorkflowInstance instance = new WorkflowInstance(); instance.setId(instanceId); - instance.setStatus(WorkflowStatusEnum.RUNNING); + instance.setStatus(WorkflowInstanceStatusEnum.RUNNING); NodeInstance runningNode = new NodeInstance(); runningNode.setStatus(NodeStatusEnum.RUNNING); @@ -261,7 +263,7 @@ class DefaultWorkflowEngineTest { workflowEngine.pauseWorkflow(instanceId); // 验证结果 - assertEquals(WorkflowStatusEnum.PAUSED, instance.getStatus()); + assertEquals(WorkflowInstanceStatusEnum.PAUSED, instance.getStatus()); assertEquals(NodeStatusEnum.PAUSED, runningNode.getStatus()); verify(workflowInstanceRepository).findById(instanceId); @@ -276,7 +278,7 @@ class DefaultWorkflowEngineTest { Long instanceId = 1L; WorkflowInstance instance = new WorkflowInstance(); instance.setId(instanceId); - instance.setStatus(WorkflowStatusEnum.PAUSED); + instance.setStatus(WorkflowInstanceStatusEnum.PAUSED); NodeInstance pausedNode = new NodeInstance(); pausedNode.setId(2L); @@ -294,7 +296,7 @@ class DefaultWorkflowEngineTest { workflowEngine.resumeWorkflow(instanceId); // 验证结果 - assertEquals(WorkflowStatusEnum.RUNNING, instance.getStatus()); + assertEquals(WorkflowInstanceStatusEnum.RUNNING, instance.getStatus()); assertEquals(NodeStatusEnum.RUNNING, pausedNode.getStatus()); verify(workflowInstanceRepository).findById(instanceId); diff --git a/backend/src/test/java/com/qqchen/deploy/backend/workflow/service/WorkflowDefinitionServiceTest.java b/backend/src/test/java/com/qqchen/deploy/backend/workflow/service/WorkflowDefinitionServiceTest.java index 435c4f7b..0c64a4ca 100644 --- a/backend/src/test/java/com/qqchen/deploy/backend/workflow/service/WorkflowDefinitionServiceTest.java +++ b/backend/src/test/java/com/qqchen/deploy/backend/workflow/service/WorkflowDefinitionServiceTest.java @@ -4,7 +4,7 @@ import com.qqchen.deploy.backend.framework.enums.ResponseCode; import com.qqchen.deploy.backend.framework.exception.BusinessException; import com.qqchen.deploy.backend.workflow.dto.WorkflowDefinitionDTO; import com.qqchen.deploy.backend.workflow.entity.WorkflowDefinition; -import com.qqchen.deploy.backend.workflow.enums.WorkflowStatusEnum; +import com.qqchen.deploy.backend.workflow.enums.WorkflowDefinitionStatusEnum; import com.qqchen.deploy.backend.workflow.repository.INodeDefinitionRepository; import com.qqchen.deploy.backend.workflow.repository.IWorkflowDefinitionRepository; import com.qqchen.deploy.backend.workflow.service.impl.WorkflowDefinitionServiceImpl; @@ -52,7 +52,7 @@ class WorkflowDefinitionServiceTest { entity.setId(1L); entity.setCode("TEST-WF"); entity.setName("Test Workflow"); - entity.setStatus(WorkflowStatusEnum.DRAFT); + entity.setStatus(WorkflowDefinitionStatusEnum.DRAFT); entity.setEnabled(true); } @@ -64,7 +64,7 @@ class WorkflowDefinitionServiceTest { WorkflowDefinitionDTO result = workflowDefinitionService.create(dto); assertNotNull(result); - assertEquals(WorkflowStatusEnum.DRAFT, result.getStatus()); + assertEquals(WorkflowDefinitionStatusEnum.DRAFT, result.getStatus()); assertTrue(result.getEnabled()); verify(workflowDefinitionRepository).existsByCodeAndDeletedFalse(dto.getCode()); verify(workflowDefinitionRepository).save(any(WorkflowDefinition.class)); @@ -81,21 +81,21 @@ class WorkflowDefinitionServiceTest { @Test void publish_Success() { - entity.setStatus(WorkflowStatusEnum.DRAFT); + entity.setStatus(WorkflowDefinitionStatusEnum.DRAFT); when(workflowDefinitionRepository.findById(anyLong())).thenReturn(Optional.of(entity)); when(workflowDefinitionRepository.save(any(WorkflowDefinition.class))).thenReturn(entity); WorkflowDefinitionDTO result = workflowDefinitionService.publish(1L); assertNotNull(result); - assertEquals(WorkflowStatusEnum.PUBLISHED, result.getStatus()); + assertEquals(WorkflowDefinitionStatusEnum.PUBLISHED, result.getStatus()); verify(workflowDefinitionRepository).findById(1L); verify(workflowDefinitionRepository).save(any(WorkflowDefinition.class)); } @Test void publish_NotDraft_ThrowsException() { - entity.setStatus(WorkflowStatusEnum.PUBLISHED); + entity.setStatus(WorkflowDefinitionStatusEnum.PUBLISHED); when(workflowDefinitionRepository.findById(anyLong())).thenReturn(Optional.of(entity)); BusinessException exception = assertThrows(BusinessException.class, @@ -105,28 +105,28 @@ class WorkflowDefinitionServiceTest { @Test void disable_Success() { - entity.setStatus(WorkflowStatusEnum.PUBLISHED); + entity.setStatus(WorkflowDefinitionStatusEnum.PUBLISHED); when(workflowDefinitionRepository.findById(anyLong())).thenReturn(Optional.of(entity)); when(workflowDefinitionRepository.save(any(WorkflowDefinition.class))).thenReturn(entity); WorkflowDefinitionDTO result = workflowDefinitionService.disable(1L); assertNotNull(result); - assertEquals(WorkflowStatusEnum.DISABLED, result.getStatus()); + assertEquals(WorkflowDefinitionStatusEnum.DISABLED, result.getStatus()); verify(workflowDefinitionRepository).findById(1L); verify(workflowDefinitionRepository).save(any(WorkflowDefinition.class)); } @Test void enable_Success() { - entity.setStatus(WorkflowStatusEnum.DISABLED); + entity.setStatus(WorkflowDefinitionStatusEnum.DISABLED); when(workflowDefinitionRepository.findById(anyLong())).thenReturn(Optional.of(entity)); when(workflowDefinitionRepository.save(any(WorkflowDefinition.class))).thenReturn(entity); WorkflowDefinitionDTO result = workflowDefinitionService.enable(1L); assertNotNull(result); - assertEquals(WorkflowStatusEnum.PUBLISHED, result.getStatus()); + assertEquals(WorkflowDefinitionStatusEnum.PUBLISHED, result.getStatus()); verify(workflowDefinitionRepository).findById(1L); verify(workflowDefinitionRepository).save(any(WorkflowDefinition.class)); } @@ -140,7 +140,7 @@ class WorkflowDefinitionServiceTest { WorkflowDefinitionDTO result = workflowDefinitionService.createNewVersion(1L); assertNotNull(result); - assertEquals(WorkflowStatusEnum.DRAFT, result.getStatus()); + assertEquals(WorkflowDefinitionStatusEnum.DRAFT, result.getStatus()); assertTrue(result.getEnabled()); verify(workflowDefinitionRepository).findById(1L); verify(workflowDefinitionRepository).findLatestVersionByCode(entity.getCode());