111
This commit is contained in:
parent
3dc944d255
commit
7bbdeefa9b
@ -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"),
|
||||
|
||||
@ -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<NodeInstance> 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<NodeInstance> 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<NodeInstance> 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<NodeInstance> pausedNodes = nodeInstanceRepository.findByWorkflowInstanceIdAndStatus(
|
||||
instanceId, NodeStatusEnum.PAUSED);
|
||||
// 重试工作流实例
|
||||
instance.retry();
|
||||
workflowInstanceRepository.save(instance);
|
||||
|
||||
for (NodeInstance node : pausedNodes) {
|
||||
node.setStatus(NodeStatusEnum.RUNNING);
|
||||
// 获取失败的节点
|
||||
List<NodeInstance> 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) {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
@ -81,10 +81,87 @@ public class WorkflowDefinition extends Entity<Long> {
|
||||
@OneToMany(mappedBy = "workflowDefinition", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
private List<NodeDefinition> nodes = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 版本号
|
||||
*/
|
||||
@Column(nullable = false)
|
||||
private Integer version = 1;
|
||||
|
||||
/**
|
||||
* 获取流转配置
|
||||
*/
|
||||
public String getTransitionConfig() {
|
||||
return transitionConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否可以发布
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -25,6 +25,12 @@ public class WorkflowInstance extends Entity<Long> {
|
||||
@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<Long> {
|
||||
public void setDefinition(WorkflowDefinition definition) {
|
||||
this.workflowDefinition = definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否可以启动
|
||||
*/
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -28,4 +28,9 @@ public interface INodeInstanceRepository extends IBaseRepository<NodeInstance, L
|
||||
List<NodeInstance> findByWorkflowInstanceId(Long workflowInstanceId);
|
||||
|
||||
void deleteByWorkflowInstanceId(Long workflowInstanceId);
|
||||
|
||||
/**
|
||||
* 查询不是指定状态的节点实例
|
||||
*/
|
||||
List<NodeInstance> findByWorkflowInstanceIdAndStatusNot(Long workflowInstanceId, NodeStatusEnum status);
|
||||
}
|
||||
@ -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;
|
||||
|
||||
/**
|
||||
@ -22,12 +24,38 @@ public interface IWorkflowInstanceRepository extends IBaseRepository<WorkflowIns
|
||||
List<WorkflowInstance> findByStatusIn(@Param("statuses") List<WorkflowInstanceStatusEnum> statuses);
|
||||
|
||||
/**
|
||||
* 根据工作流定义ID和状态查询工作流实例数量
|
||||
* 根据工作流定义ID和状态查询工作流实例
|
||||
*/
|
||||
long countByDefinitionIdAndStatus(Long definitionId, WorkflowInstanceStatusEnum status);
|
||||
List<WorkflowInstance> findByWorkflowDefinitionIdAndStatus(Long workflowDefinitionId, WorkflowInstanceStatusEnum status);
|
||||
|
||||
/**
|
||||
* 根据工作流定义ID和状态统计工作流实例数量
|
||||
*/
|
||||
Long countByWorkflowDefinitionIdAndStatus(Long workflowDefinitionId, WorkflowInstanceStatusEnum status);
|
||||
|
||||
/**
|
||||
* 查询项目环境的工作流实例
|
||||
*/
|
||||
List<WorkflowInstance> findByProjectEnvIdAndDeletedFalseOrderByCreateTimeDesc(Long projectEnvId);
|
||||
|
||||
/**
|
||||
* 查找超过指定时间未完成的工作流实例
|
||||
*/
|
||||
@Query("SELECT wi FROM WorkflowInstance wi WHERE wi.status = :status AND wi.startTime < :beforeTime")
|
||||
List<WorkflowInstance> 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<WorkflowInstance> findActiveInstancesByDefinitionId(@Param("definitionId") Long definitionId,
|
||||
@Param("activeStatuses") Collection<WorkflowInstanceStatusEnum> 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<WorkflowInstanceStatusEnum> activeStatuses);
|
||||
}
|
||||
@ -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=不支持的节点类型
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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=不支持的节点类型
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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());
|
||||
|
||||
Loading…
Reference in New Issue
Block a user