mirror of
https://github.com/PowerJob/PowerJob.git
synced 2025-07-17 00:00:04 +08:00
fix: the problem of retrying nested workflow node
This commit is contained in:
parent
d4eb8e3303
commit
5791b43ac6
@ -26,8 +26,6 @@ import java.util.Date;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import static tech.powerjob.server.core.workflow.algorithm.WorkflowDAGUtils.isNotAllowSkipWhenFailed;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 工作流实例服务
|
* 工作流实例服务
|
||||||
*
|
*
|
||||||
@ -135,13 +133,7 @@ public class WorkflowInstanceService {
|
|||||||
if (!workflowInfo.isPresent() || workflowInfo.get().getStatus() == SwitchableStatus.DISABLE.getV()) {
|
if (!workflowInfo.isPresent() || workflowInfo.get().getStatus() == SwitchableStatus.DISABLE.getV()) {
|
||||||
throw new PowerJobException("you can't retry the workflow instance whose metadata is unavailable!");
|
throw new PowerJobException("you can't retry the workflow instance whose metadata is unavailable!");
|
||||||
}
|
}
|
||||||
// 将需要重试的节点状态重置(失败且不允许跳过的 或者 手动终止的)
|
WorkflowDAGUtils.resetRetryableNode(dag);
|
||||||
for (PEWorkflowDAG.Node node : dag.getNodes()) {
|
|
||||||
boolean realFailed = node.getStatus() == InstanceStatus.FAILED.getV() && isNotAllowSkipWhenFailed(node);
|
|
||||||
if (realFailed || node.getStatus() == InstanceStatus.STOPPED.getV()) {
|
|
||||||
node.setStatus(InstanceStatus.WAITING_DISPATCH.getV()).setInstanceId(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
wfInstance.setDag(JSON.toJSONString(dag));
|
wfInstance.setDag(JSON.toJSONString(dag));
|
||||||
// 更新工作流实例状态,不覆盖实际触发时间
|
// 更新工作流实例状态,不覆盖实际触发时间
|
||||||
wfInstance.setStatus(WorkflowInstanceStatus.WAITING.getV());
|
wfInstance.setStatus(WorkflowInstanceStatus.WAITING.getV());
|
||||||
|
@ -3,6 +3,7 @@ package tech.powerjob.server.core.workflow.algorithm;
|
|||||||
import com.google.common.collect.*;
|
import com.google.common.collect.*;
|
||||||
import tech.powerjob.common.SystemInstanceResult;
|
import tech.powerjob.common.SystemInstanceResult;
|
||||||
import tech.powerjob.common.enums.InstanceStatus;
|
import tech.powerjob.common.enums.InstanceStatus;
|
||||||
|
import tech.powerjob.common.enums.WorkflowNodeType;
|
||||||
import tech.powerjob.common.exception.PowerJobException;
|
import tech.powerjob.common.exception.PowerJobException;
|
||||||
import tech.powerjob.common.model.PEWorkflowDAG;
|
import tech.powerjob.common.model.PEWorkflowDAG;
|
||||||
import tech.powerjob.common.serialize.JsonUtils;
|
import tech.powerjob.common.serialize.JsonUtils;
|
||||||
@ -22,6 +23,24 @@ public class WorkflowDAGUtils {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置可重试节点的状态信息
|
||||||
|
* @param dag 合法的有向无环图
|
||||||
|
*/
|
||||||
|
public static void resetRetryableNode(PEWorkflowDAG dag){
|
||||||
|
// 将需要重试的节点状态重置(失败且不允许跳过的 或者 手动终止的)
|
||||||
|
for (PEWorkflowDAG.Node node : dag.getNodes()) {
|
||||||
|
boolean realFailed = node.getStatus() == InstanceStatus.FAILED.getV() && isNotAllowSkipWhenFailed(node);
|
||||||
|
if (realFailed || node.getStatus() == InstanceStatus.STOPPED.getV()) {
|
||||||
|
node.setStatus(InstanceStatus.WAITING_DISPATCH.getV());
|
||||||
|
// 仅重置任务节点的实例 id 信息
|
||||||
|
if (node.getNodeType() == null || node.getNodeType() == WorkflowNodeType.JOB.getCode()){
|
||||||
|
node.setInstanceId(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取所有根节点
|
* 获取所有根节点
|
||||||
*
|
*
|
||||||
@ -173,9 +192,9 @@ public class WorkflowDAGUtils {
|
|||||||
private static boolean isReadyNode(long nodeId, Map<Long, PEWorkflowDAG.Node> nodeId2Node, Multimap<Long, Long> relyMap) {
|
private static boolean isReadyNode(long nodeId, Map<Long, PEWorkflowDAG.Node> nodeId2Node, Multimap<Long, Long> relyMap) {
|
||||||
PEWorkflowDAG.Node currentNode = nodeId2Node.get(nodeId);
|
PEWorkflowDAG.Node currentNode = nodeId2Node.get(nodeId);
|
||||||
int currentNodeStatus = currentNode.getStatus() == null ? InstanceStatus.WAITING_DISPATCH.getV() : currentNode.getStatus();
|
int currentNodeStatus = currentNode.getStatus() == null ? InstanceStatus.WAITING_DISPATCH.getV() : currentNode.getStatus();
|
||||||
// 跳过已完成节点(处理成功 或者 处理失败)和已派发节点(存在 InstanceId)
|
// 跳过已完成节点(处理成功 或者 处理失败)和已派发节点( 状态为运行中 )
|
||||||
if (InstanceStatus.FINISHED_STATUS.contains(currentNodeStatus)
|
if (InstanceStatus.FINISHED_STATUS.contains(currentNodeStatus)
|
||||||
|| currentNode.getInstanceId() != null) {
|
|| currentNodeStatus == InstanceStatus.RUNNING.getV()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Collection<Long> relyNodeIds = relyMap.get(nodeId);
|
Collection<Long> relyNodeIds = relyMap.get(nodeId);
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package tech.powerjob.server.core.workflow.hanlder.impl;
|
package tech.powerjob.server.core.workflow.hanlder.impl;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
import tech.powerjob.common.SystemInstanceResult;
|
||||||
import tech.powerjob.common.enums.InstanceStatus;
|
import tech.powerjob.common.enums.InstanceStatus;
|
||||||
import tech.powerjob.common.enums.WorkflowInstanceStatus;
|
import tech.powerjob.common.enums.WorkflowInstanceStatus;
|
||||||
import tech.powerjob.common.enums.WorkflowNodeType;
|
import tech.powerjob.common.enums.WorkflowNodeType;
|
||||||
@ -10,6 +12,7 @@ import tech.powerjob.common.model.PEWorkflowDAG;
|
|||||||
import tech.powerjob.common.utils.CommonUtils;
|
import tech.powerjob.common.utils.CommonUtils;
|
||||||
import tech.powerjob.server.common.constants.SwitchableStatus;
|
import tech.powerjob.server.common.constants.SwitchableStatus;
|
||||||
import tech.powerjob.server.core.workflow.WorkflowInstanceManager;
|
import tech.powerjob.server.core.workflow.WorkflowInstanceManager;
|
||||||
|
import tech.powerjob.server.core.workflow.algorithm.WorkflowDAGUtils;
|
||||||
import tech.powerjob.server.core.workflow.hanlder.TaskNodeHandler;
|
import tech.powerjob.server.core.workflow.hanlder.TaskNodeHandler;
|
||||||
import tech.powerjob.server.persistence.remote.model.WorkflowInfoDO;
|
import tech.powerjob.server.persistence.remote.model.WorkflowInfoDO;
|
||||||
import tech.powerjob.server.persistence.remote.model.WorkflowInstanceInfoDO;
|
import tech.powerjob.server.persistence.remote.model.WorkflowInstanceInfoDO;
|
||||||
@ -50,15 +53,28 @@ public class NestedWorkflowNodeHandler implements TaskNodeHandler {
|
|||||||
throw new PowerJobException("invalid nested workflow node," + node.getNodeId());
|
throw new PowerJobException("invalid nested workflow node," + node.getNodeId());
|
||||||
}
|
}
|
||||||
if (node.getInstanceId() != null) {
|
if (node.getInstanceId() != null) {
|
||||||
// 处理重试的情形,不需要创建实例,仅需要更改对应实例的状态
|
// 处理重试的情形,不需要创建实例,仅需要更改对应实例的状态,以及相应的节点状态
|
||||||
WorkflowInstanceInfoDO wfInstance = workflowInstanceInfoRepository.findByWfInstanceId(node.getInstanceId()).orElse(null);
|
WorkflowInstanceInfoDO wfInstance = workflowInstanceInfoRepository.findByWfInstanceId(node.getInstanceId()).orElse(null);
|
||||||
if (wfInstance == null) {
|
if (wfInstance == null) {
|
||||||
log.error("[Workflow-{}|{}] invalid nested workflow node({}),target workflow instance({}) is not exist!", wfInstanceInfo.getWorkflowId(), wfInstanceInfo.getWfInstanceId(), node.getNodeId(), node.getInstanceId());
|
log.error("[Workflow-{}|{}] invalid nested workflow node({}),target workflow instance({}) is not exist!", wfInstanceInfo.getWorkflowId(), wfInstanceInfo.getWfInstanceId(), node.getNodeId(), node.getInstanceId());
|
||||||
throw new PowerJobException("invalid workflow instance id" + node.getNodeId());
|
throw new PowerJobException("invalid nested workflow instance id " + node.getInstanceId());
|
||||||
|
}
|
||||||
|
// 不用考虑状态,只有失败的工作流嵌套节点状态会被重置
|
||||||
|
// 需要将子工作流中失败的节点状态重置为 等待 派发
|
||||||
|
try {
|
||||||
|
PEWorkflowDAG nodeDag = JSON.parseObject(wfInstance.getDag(), PEWorkflowDAG.class);
|
||||||
|
if (!WorkflowDAGUtils.valid(nodeDag)) {
|
||||||
|
throw new PowerJobException(SystemInstanceResult.INVALID_DAG);
|
||||||
|
}
|
||||||
|
WorkflowDAGUtils.resetRetryableNode(nodeDag);
|
||||||
|
wfInstance.setDag(JSON.toJSONString(nodeDag));
|
||||||
|
wfInstance.setStatus(WorkflowInstanceStatus.WAITING.getV());
|
||||||
|
wfInstance.setGmtModified(new Date());
|
||||||
|
workflowInstanceInfoRepository.saveAndFlush(wfInstance);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("[Workflow-{}|{}] invalid nested workflow node({}),target workflow instance({})'s DAG is illegal!", wfInstanceInfo.getWorkflowId(), wfInstanceInfo.getWfInstanceId(), node.getNodeId(), node.getInstanceId(),e);
|
||||||
|
throw new PowerJobException("illegal nested workflow instance, id : "+ node.getInstanceId());
|
||||||
}
|
}
|
||||||
wfInstance.setStatus(WorkflowInstanceStatus.WAITING.getV());
|
|
||||||
wfInstance.setGmtModified(new Date());
|
|
||||||
workflowInstanceInfoRepository.saveAndFlush(wfInstance);
|
|
||||||
} else {
|
} else {
|
||||||
// 透传当前的上下文创建新的工作流实例
|
// 透传当前的上下文创建新的工作流实例
|
||||||
String wfContext = wfInstanceInfo.getWfContext();
|
String wfContext = wfInstanceInfo.getWfContext();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user