可执行一个简单的工作流。
This commit is contained in:
parent
4b4d35fccd
commit
f5fb0a2dae
@ -124,7 +124,7 @@ public class DefaultWorkflowEngine implements WorkflowEngine {
|
||||
startNode.setNodeType(startNodeConfig.getType());
|
||||
startNode.setName(startNodeConfig.getName());
|
||||
startNode.setConfig(objectMapper.writeValueAsString(startNodeConfig.getConfig()));
|
||||
startNode.setStatus(NodeStatusEnum.PENDING);
|
||||
startNode.setStatus(NodeStatusEnum.RUNNING);
|
||||
startNode.setCreateTime(LocalDateTime.now());
|
||||
nodeInstanceRepository.save(startNode);
|
||||
|
||||
@ -203,7 +203,6 @@ public class DefaultWorkflowEngine implements WorkflowEngine {
|
||||
.findByWorkflowInstanceAndStatusNot(instance, NodeStatusEnum.COMPLETED);
|
||||
|
||||
if (uncompletedNodes.isEmpty()) {
|
||||
instance.complete();
|
||||
workflowInstanceRepository.save(instance);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@ -223,21 +222,18 @@ public class DefaultWorkflowEngine implements WorkflowEngine {
|
||||
}
|
||||
|
||||
private void createAndExecuteNextNode(WorkflowInstance instance, String nextNodeId, NodeConfig nodeConfig) {
|
||||
try {
|
||||
NodeInstance nextNode = new NodeInstance();
|
||||
nextNode.setNodeId(nextNodeId);
|
||||
nextNode.setWorkflowInstance(instance);
|
||||
nextNode.setNodeType(nodeConfig.getType());
|
||||
nextNode.setName(nodeConfig.getName());
|
||||
nextNode.setConfig(objectMapper.writeValueAsString(nodeConfig.getConfig()));
|
||||
nextNode.setStatus(NodeStatusEnum.PENDING);
|
||||
nodeInstanceRepository.save(nextNode);
|
||||
NodeInstance nextNode = new NodeInstance();
|
||||
nextNode.setNodeId(nextNodeId);
|
||||
nextNode.setWorkflowInstance(instance);
|
||||
nextNode.setNodeType(nodeConfig.getType());
|
||||
nextNode.setName(nodeConfig.getName());
|
||||
// nextNode.setConfigObject(nodeExecuteConfigConverter.toNodeExecutorConfig(nodeConfig));
|
||||
// nextNode.setConfigObject(nodeConfig);
|
||||
nextNode.setStatus(NodeStatusEnum.PENDING);
|
||||
nodeInstanceRepository.save(nextNode);
|
||||
|
||||
// 递归执行后续节点
|
||||
executeNode(nextNode.getId());
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new WorkflowEngineException(ResponseCode.WORKFLOW_NODE_CONFIG_INVALID, e);
|
||||
}
|
||||
// 递归执行后续节点
|
||||
executeNode(nextNode.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -15,6 +15,5 @@ public class WorkflowEngineException extends BusinessException {
|
||||
|
||||
public WorkflowEngineException(ResponseCode code, Throwable cause) {
|
||||
super(code, new Object[]{cause.getMessage()});
|
||||
initCause(cause);
|
||||
}
|
||||
}
|
||||
@ -5,9 +5,10 @@ import com.qqchen.deploy.backend.system.enums.LogLevelEnum;
|
||||
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
|
||||
import com.qqchen.deploy.backend.workflow.engine.exception.WorkflowEngineException;
|
||||
import com.qqchen.deploy.backend.workflow.engine.context.WorkflowContextOperations;
|
||||
import com.qqchen.deploy.backend.workflow.engine.executor.node.config.ScriptNodeConfig;
|
||||
import com.qqchen.deploy.backend.workflow.engine.executor.node.config.ScriptNodeExecutorConfig;
|
||||
import com.qqchen.deploy.backend.workflow.entity.NodeInstance;
|
||||
import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnum;
|
||||
import com.qqchen.deploy.backend.workflow.enums.ScriptLanguageEnum;
|
||||
import com.qqchen.deploy.backend.workflow.service.WorkflowVariableOperations;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
@ -51,7 +52,7 @@ public class ScriptNodeExecutor extends AbstractNodeExecutor {
|
||||
@Override
|
||||
public void validate(String config) {
|
||||
try {
|
||||
ScriptNodeConfig scriptConfig = objectMapper.readValue(config, ScriptNodeConfig.class);
|
||||
ScriptNodeExecutorConfig scriptConfig = objectMapper.readValue(config, ScriptNodeExecutorConfig.class);
|
||||
// 验证脚本内容
|
||||
if (scriptConfig.getScript() == null || scriptConfig.getScript().trim().isEmpty()) {
|
||||
throw new WorkflowEngineException(ResponseCode.WORKFLOW_NODE_CONFIG_ERROR, "Script content cannot be empty");
|
||||
@ -78,40 +79,44 @@ public class ScriptNodeExecutor extends AbstractNodeExecutor {
|
||||
@Override
|
||||
protected void doExecute(NodeInstance nodeInstance, WorkflowContextOperations context) {
|
||||
try {
|
||||
String configJson = nodeInstance.getConfig();
|
||||
ScriptNodeConfig config = objectMapper.readValue(configJson, ScriptNodeConfig.class);
|
||||
|
||||
// 设置重试次数和间隔
|
||||
int maxAttempts = config.getRetryTimes() != null ? config.getRetryTimes() : 1;
|
||||
long retryInterval = config.getRetryInterval() != null ? config.getRetryInterval() : 0;
|
||||
|
||||
Exception lastException = null;
|
||||
for (int attempt = 1; attempt <= maxAttempts; attempt++) {
|
||||
try {
|
||||
// 执行脚本
|
||||
// String configJson = nodeInstance.getConfig();
|
||||
// ScriptNodeExecutorConfig config = objectMapper.readValue(configJson, ScriptNodeExecutorConfig.class);
|
||||
//
|
||||
// // 设置重试次数和间隔
|
||||
// int maxAttempts = config.getRetryTimes() != null ? config.getRetryTimes() : 1;
|
||||
// long retryInterval = config.getRetryInterval() != null ? config.getRetryInterval() : 0;
|
||||
//
|
||||
// Exception lastException = null;
|
||||
// for (int attempt = 1; attempt <= maxAttempts; attempt++) {
|
||||
// try {
|
||||
// // 执行脚本
|
||||
ScriptNodeExecutorConfig config = new ScriptNodeExecutorConfig();
|
||||
config.setLanguage(ScriptLanguageEnum.SHELL);
|
||||
config.setInterpreter("/bin/bash");
|
||||
config.setScript("ls -a");
|
||||
executeScript(config, nodeInstance, context);
|
||||
return; // 执行成功,直接返回
|
||||
} catch (Exception e) {
|
||||
lastException = e;
|
||||
if (attempt < maxAttempts) {
|
||||
context.log(String.format("Script execution failed (attempt %d/%d), retrying in %d seconds",
|
||||
attempt, maxAttempts, retryInterval), LogLevelEnum.WARN);
|
||||
Thread.sleep(retryInterval * 1000L);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果所有重试都失败,抛出最后一个异常
|
||||
if (lastException != null) {
|
||||
throw lastException;
|
||||
}
|
||||
|
||||
// return; // 执行成功,直接返回
|
||||
// } catch (Exception e) {
|
||||
// lastException = e;
|
||||
// if (attempt < maxAttempts) {
|
||||
// context.log(String.format("Script execution failed (attempt %d/%d), retrying in %d seconds",
|
||||
// attempt, maxAttempts, retryInterval), LogLevelEnum.WARN);
|
||||
// Thread.sleep(retryInterval * 1000L);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 如果所有重试都失败,抛出最后一个异常
|
||||
// if (lastException != null) {
|
||||
// throw lastException;
|
||||
// }
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new WorkflowEngineException(ResponseCode.WORKFLOW_NODE_EXECUTION_FAILED, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void executeScript(ScriptNodeConfig config, NodeInstance nodeInstance, WorkflowContextOperations context) throws Exception {
|
||||
private void executeScript(ScriptNodeExecutorConfig config, NodeInstance nodeInstance, WorkflowContextOperations context) throws Exception {
|
||||
ProcessBuilder processBuilder = new ProcessBuilder();
|
||||
|
||||
// 获取命令实现并构建命令
|
||||
|
||||
@ -5,7 +5,7 @@ import com.qqchen.deploy.backend.system.enums.LogLevelEnum;
|
||||
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
|
||||
import com.qqchen.deploy.backend.workflow.engine.exception.WorkflowEngineException;
|
||||
import com.qqchen.deploy.backend.workflow.engine.context.WorkflowContextOperations;
|
||||
import com.qqchen.deploy.backend.workflow.engine.executor.node.config.ShellNodeConfig;
|
||||
import com.qqchen.deploy.backend.workflow.engine.executor.node.config.ShellNodeExecutorConfig;
|
||||
import com.qqchen.deploy.backend.workflow.entity.NodeInstance;
|
||||
import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnum;
|
||||
import com.qqchen.deploy.backend.workflow.service.WorkflowVariableOperations;
|
||||
@ -46,7 +46,7 @@ public class ShellNodeExecutor extends AbstractNodeExecutor {
|
||||
@Override
|
||||
public void validate(String config) {
|
||||
try {
|
||||
ShellNodeConfig shellConfig = objectMapper.readValue(config, ShellNodeConfig.class);
|
||||
ShellNodeExecutorConfig shellConfig = objectMapper.readValue(config, ShellNodeExecutorConfig.class);
|
||||
// 验证执行器类型
|
||||
if (!"SHELL".equals(shellConfig.getExecutor())) {
|
||||
throw new WorkflowEngineException(ResponseCode.WORKFLOW_NODE_CONFIG_ERROR);
|
||||
@ -74,7 +74,7 @@ public class ShellNodeExecutor extends AbstractNodeExecutor {
|
||||
protected void doExecute(NodeInstance nodeInstance, WorkflowContextOperations context) {
|
||||
try {
|
||||
String configJson = nodeInstance.getConfig();
|
||||
ShellNodeConfig config = objectMapper.readValue(configJson, ShellNodeConfig.class);
|
||||
ShellNodeExecutorConfig config = objectMapper.readValue(configJson, ShellNodeExecutorConfig.class);
|
||||
|
||||
// 验证执行器类型
|
||||
if (!"SHELL".equals(config.getExecutor())) {
|
||||
@ -110,7 +110,7 @@ public class ShellNodeExecutor extends AbstractNodeExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
private void executeShellCommand(ShellNodeConfig config, NodeInstance nodeInstance, WorkflowContextOperations context) throws Exception {
|
||||
private void executeShellCommand(ShellNodeExecutorConfig config, NodeInstance nodeInstance, WorkflowContextOperations context) throws Exception {
|
||||
ProcessBuilder processBuilder = new ProcessBuilder();
|
||||
processBuilder.command("sh", "-c", config.getScript());
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ import java.util.List;
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ApprovalNodeConfig extends NodeConfig {
|
||||
public class ApprovalNodeExecutorConfig extends NodeExecutorConfig {
|
||||
|
||||
/**
|
||||
* 审批人类型:USER-指定用户,ROLE-指定角色,LEADER-直属领导
|
||||
@ -9,7 +9,7 @@ import java.util.List;
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ConditionNodeConfig extends NodeConfig {
|
||||
public class ConditionNodeExecutorConfig extends NodeExecutorConfig {
|
||||
|
||||
/**
|
||||
* 条件表达式(使用SpEL表达式)
|
||||
@ -8,7 +8,7 @@ import lombok.EqualsAndHashCode;
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class GitNodeConfig extends NodeConfig {
|
||||
public class GitNodeExecutorConfig extends NodeExecutorConfig {
|
||||
|
||||
/**
|
||||
* Git仓库URL
|
||||
@ -9,7 +9,7 @@ import java.util.Map;
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class HttpNodeConfig extends NodeConfig {
|
||||
public class HttpNodeExecutorConfig extends NodeExecutorConfig {
|
||||
|
||||
/**
|
||||
* 请求URL
|
||||
@ -9,7 +9,7 @@ import java.util.Map;
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class JenkinsNodeConfig extends NodeConfig {
|
||||
public class JenkinsNodeExecutorConfig extends NodeExecutorConfig {
|
||||
|
||||
/**
|
||||
* Jenkins服务器ID
|
||||
@ -9,7 +9,7 @@ import java.util.Map;
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class NacosNodeConfig extends NodeConfig {
|
||||
public class NacosNodeExecutorConfig extends NodeExecutorConfig {
|
||||
|
||||
/**
|
||||
* Nacos服务器ID
|
||||
@ -1,66 +0,0 @@
|
||||
package com.qqchen.deploy.backend.workflow.engine.executor.node.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnum;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 节点配置基类
|
||||
*/
|
||||
@Data
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
|
||||
@JsonSubTypes({
|
||||
@JsonSubTypes.Type(value = ApprovalNodeConfig.class, name = "APPROVAL"),
|
||||
@JsonSubTypes.Type(value = ScriptNodeConfig.class, name = "SCRIPT"),
|
||||
@JsonSubTypes.Type(value = ShellNodeConfig.class, name = "SHELL"),
|
||||
@JsonSubTypes.Type(value = JenkinsNodeConfig.class, name = "JENKINS"),
|
||||
@JsonSubTypes.Type(value = GitNodeConfig.class, name = "GIT"),
|
||||
@JsonSubTypes.Type(value = ConditionNodeConfig.class, name = "CONDITION"),
|
||||
@JsonSubTypes.Type(value = ParallelNodeConfig.class, name = "PARALLEL"),
|
||||
@JsonSubTypes.Type(value = NacosNodeConfig.class, name = "NACOS"),
|
||||
@JsonSubTypes.Type(value = HttpNodeConfig.class, name = "HTTP"),
|
||||
@JsonSubTypes.Type(value = NotifyNodeConfig.class, name = "NOTIFY")
|
||||
})
|
||||
public abstract class NodeConfig {
|
||||
|
||||
/**
|
||||
* 节点ID
|
||||
*/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 节点名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 节点类型
|
||||
*/
|
||||
private NodeTypeEnum type;
|
||||
|
||||
/**
|
||||
* 超时时间(分钟)
|
||||
*/
|
||||
private Integer timeout;
|
||||
|
||||
/**
|
||||
* 重试次数
|
||||
*/
|
||||
private Integer retryCount;
|
||||
|
||||
/**
|
||||
* 重试间隔(秒)
|
||||
*/
|
||||
private Integer retryInterval;
|
||||
|
||||
/**
|
||||
* 失败是否继续
|
||||
*/
|
||||
private Boolean continueOnFailed;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
private String description;
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
package com.qqchen.deploy.backend.workflow.engine.executor.node.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnum;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 节点配置基类
|
||||
*/
|
||||
@Data
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true) // 忽略未知字段
|
||||
@JsonSubTypes({
|
||||
@JsonSubTypes.Type(value = ApprovalNodeExecutorConfig.class, name = "APPROVAL"),
|
||||
@JsonSubTypes.Type(value = ScriptNodeExecutorConfig.class, name = "SCRIPT"),
|
||||
@JsonSubTypes.Type(value = ShellNodeExecutorConfig.class, name = "SHELL"),
|
||||
@JsonSubTypes.Type(value = JenkinsNodeExecutorConfig.class, name = "JENKINS"),
|
||||
@JsonSubTypes.Type(value = GitNodeExecutorConfig.class, name = "GIT"),
|
||||
@JsonSubTypes.Type(value = ConditionNodeExecutorConfig.class, name = "CONDITION"),
|
||||
@JsonSubTypes.Type(value = ParallelNodeExecutorConfig.class, name = "PARALLEL"),
|
||||
@JsonSubTypes.Type(value = NacosNodeExecutorConfig.class, name = "NACOS"),
|
||||
@JsonSubTypes.Type(value = HttpNodeExecutorConfig.class, name = "HTTP"),
|
||||
@JsonSubTypes.Type(value = NotifyNodeExecutorConfig.class, name = "NOTIFY")
|
||||
})
|
||||
public class NodeExecutorConfig {
|
||||
|
||||
/**
|
||||
* 节点ID
|
||||
*/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 节点名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 节点类型
|
||||
*/
|
||||
private NodeTypeEnum type;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
private String description;
|
||||
}
|
||||
@ -10,7 +10,7 @@ import java.util.Map;
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class NotifyNodeConfig extends NodeConfig {
|
||||
public class NotifyNodeExecutorConfig extends NodeExecutorConfig {
|
||||
|
||||
/**
|
||||
* 通知类型:EMAIL-邮件,SMS-短信,DINGTALK-钉钉,WEIXIN-企业微信
|
||||
@ -9,7 +9,7 @@ import java.util.List;
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ParallelNodeConfig extends NodeConfig {
|
||||
public class ParallelNodeExecutorConfig extends NodeExecutorConfig {
|
||||
|
||||
/**
|
||||
* 并行分支列表
|
||||
@ -12,7 +12,7 @@ import java.util.Map;
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ScriptNodeConfig extends NodeConfig {
|
||||
public class ScriptNodeExecutorConfig extends NodeExecutorConfig {
|
||||
/**
|
||||
* 脚本内容
|
||||
*/
|
||||
@ -39,16 +39,6 @@ public class ScriptNodeConfig extends NodeConfig {
|
||||
*/
|
||||
private Integer timeout;
|
||||
|
||||
/**
|
||||
* 环境变量
|
||||
*/
|
||||
private Map<String, String> environment;
|
||||
|
||||
/**
|
||||
* 成功退出码
|
||||
*/
|
||||
private Integer successExitCode = 0;
|
||||
|
||||
/**
|
||||
* 重试次数
|
||||
*/
|
||||
@ -60,15 +50,17 @@ public class ScriptNodeConfig extends NodeConfig {
|
||||
private Integer retryInterval;
|
||||
|
||||
/**
|
||||
* 脚本参数
|
||||
* 环境变量
|
||||
*/
|
||||
private Map<String, String> arguments;
|
||||
private Map<String, String> environment;
|
||||
|
||||
public String getScript() {
|
||||
return script;
|
||||
}
|
||||
/**
|
||||
* 成功退出码
|
||||
*/
|
||||
private Integer successExitCode = 0;
|
||||
|
||||
public Map<String, String> getEnvironment() {
|
||||
return environment;
|
||||
}
|
||||
/**
|
||||
* 失败是否继续
|
||||
*/
|
||||
private Boolean continueOnFailed;
|
||||
}
|
||||
@ -7,12 +7,12 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* Shell节点配置
|
||||
* @deprecated 请使用 {@link ScriptNodeConfig} 替代,设置 language="shell"
|
||||
* @deprecated 请使用 {@link ScriptNodeExecutorConfig} 替代,设置 language="shell"
|
||||
*/
|
||||
@Deprecated(since = "1.0", forRemoval = true)
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ShellNodeConfig extends NodeConfig {
|
||||
public class ShellNodeExecutorConfig extends NodeExecutorConfig {
|
||||
/**
|
||||
* 执行器类型,固定为 SHELL
|
||||
*/
|
||||
@ -1,6 +1,6 @@
|
||||
package com.qqchen.deploy.backend.workflow.engine.executor.node.script.command;
|
||||
|
||||
import com.qqchen.deploy.backend.workflow.engine.executor.node.config.ScriptNodeConfig;
|
||||
import com.qqchen.deploy.backend.workflow.engine.executor.node.config.ScriptNodeExecutorConfig;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -12,5 +12,5 @@ public interface ScriptCommand {
|
||||
* @param config 脚本配置
|
||||
* @return 命令行参数列表
|
||||
*/
|
||||
List<String> buildCommand(ScriptNodeConfig config);
|
||||
List<String> buildCommand(ScriptNodeExecutorConfig config);
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ package com.qqchen.deploy.backend.workflow.engine.executor.node.script.command.i
|
||||
|
||||
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
|
||||
import com.qqchen.deploy.backend.workflow.engine.exception.WorkflowEngineException;
|
||||
import com.qqchen.deploy.backend.workflow.engine.executor.node.config.ScriptNodeConfig;
|
||||
import com.qqchen.deploy.backend.workflow.engine.executor.node.config.ScriptNodeExecutorConfig;
|
||||
import com.qqchen.deploy.backend.workflow.engine.executor.node.script.command.ScriptCommand;
|
||||
import com.qqchen.deploy.backend.workflow.engine.executor.node.script.command.ScriptLanguageSupport;
|
||||
import com.qqchen.deploy.backend.workflow.enums.ScriptLanguageEnum;
|
||||
@ -17,7 +17,7 @@ import java.util.List;
|
||||
@ScriptLanguageSupport(ScriptLanguageEnum.PYTHON)
|
||||
public class PythonScriptCommand implements ScriptCommand {
|
||||
@Override
|
||||
public List<String> buildCommand(ScriptNodeConfig config) {
|
||||
public List<String> buildCommand(ScriptNodeExecutorConfig config) {
|
||||
if (config.getInterpreter() == null || config.getInterpreter().trim().isEmpty()) {
|
||||
throw new WorkflowEngineException(ResponseCode.WORKFLOW_NODE_CONFIG_ERROR,
|
||||
"Python interpreter path must be specified");
|
||||
|
||||
@ -2,7 +2,7 @@ package com.qqchen.deploy.backend.workflow.engine.executor.node.script.command.i
|
||||
|
||||
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
|
||||
import com.qqchen.deploy.backend.workflow.engine.exception.WorkflowEngineException;
|
||||
import com.qqchen.deploy.backend.workflow.engine.executor.node.config.ScriptNodeConfig;
|
||||
import com.qqchen.deploy.backend.workflow.engine.executor.node.config.ScriptNodeExecutorConfig;
|
||||
import com.qqchen.deploy.backend.workflow.engine.executor.node.script.command.ScriptCommand;
|
||||
import com.qqchen.deploy.backend.workflow.engine.executor.node.script.command.ScriptLanguageSupport;
|
||||
import com.qqchen.deploy.backend.workflow.enums.ScriptLanguageEnum;
|
||||
@ -17,7 +17,7 @@ import java.util.List;
|
||||
@ScriptLanguageSupport(ScriptLanguageEnum.SHELL)
|
||||
public class ShellScriptCommand implements ScriptCommand {
|
||||
@Override
|
||||
public List<String> buildCommand(ScriptNodeConfig config) {
|
||||
public List<String> buildCommand(ScriptNodeExecutorConfig config) {
|
||||
if (config.getInterpreter() == null || config.getInterpreter().trim().isEmpty()) {
|
||||
throw new WorkflowEngineException(ResponseCode.WORKFLOW_NODE_CONFIG_ERROR,
|
||||
"Shell interpreter path must be specified");
|
||||
|
||||
@ -1,7 +1,12 @@
|
||||
package com.qqchen.deploy.backend.workflow.entity;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.qqchen.deploy.backend.framework.annotation.LogicDelete;
|
||||
import com.qqchen.deploy.backend.framework.domain.Entity;
|
||||
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
|
||||
import com.qqchen.deploy.backend.framework.utils.SpringUtils;
|
||||
import com.qqchen.deploy.backend.workflow.engine.exception.WorkflowEngineException;
|
||||
import com.qqchen.deploy.backend.workflow.engine.executor.node.config.NodeExecutorConfig;
|
||||
import com.qqchen.deploy.backend.workflow.enums.NodeStatusEnum;
|
||||
import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnum;
|
||||
import jakarta.persistence.*;
|
||||
@ -10,6 +15,9 @@ import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@jakarta.persistence.Entity
|
||||
@ -18,77 +26,84 @@ import java.time.LocalDateTime;
|
||||
public class NodeInstance extends Entity<Long> {
|
||||
|
||||
/**
|
||||
* 工作流实例
|
||||
*
|
||||
*/
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "workflow_instance_id", nullable = false)
|
||||
private WorkflowInstance workflowInstance;
|
||||
|
||||
/**
|
||||
* 节点ID
|
||||
* ID
|
||||
*/
|
||||
@Column(nullable = false)
|
||||
private String nodeId;
|
||||
|
||||
/**
|
||||
* 节点类型
|
||||
*
|
||||
*/
|
||||
@Enumerated(EnumType.ORDINAL)
|
||||
@Column(nullable = false)
|
||||
private NodeTypeEnum nodeType;
|
||||
|
||||
/**
|
||||
* 节点名称
|
||||
*
|
||||
*/
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 节点状态
|
||||
*
|
||||
*/
|
||||
@Enumerated(EnumType.ORDINAL)
|
||||
@Column(nullable = false)
|
||||
private NodeStatusEnum status;
|
||||
|
||||
/**
|
||||
* 开始时间
|
||||
*
|
||||
*/
|
||||
private LocalDateTime startTime;
|
||||
|
||||
/**
|
||||
* 结束时间
|
||||
*
|
||||
*/
|
||||
private LocalDateTime endTime;
|
||||
|
||||
/**
|
||||
* 节点配置(JSON)
|
||||
* (JSON)
|
||||
*/
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private String config;
|
||||
|
||||
/**
|
||||
* 输入参数(JSON)
|
||||
* (JSON)
|
||||
*/
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private String input;
|
||||
|
||||
/**
|
||||
* 输出结果(JSON)
|
||||
* (JSON)
|
||||
*/
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private String output;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
*
|
||||
*/
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private String error;
|
||||
|
||||
/**
|
||||
* 前置节点ID
|
||||
* ID
|
||||
*/
|
||||
private String preNodeId;
|
||||
|
||||
@Transient
|
||||
private NodeExecutorConfig configObject;
|
||||
|
||||
private static ObjectMapper getObjectMapper() {
|
||||
return SpringUtils.getBean(ObjectMapper.class);
|
||||
}
|
||||
|
||||
public String getConfig() {
|
||||
return config;
|
||||
}
|
||||
@ -96,4 +111,26 @@ public class NodeInstance extends Entity<Long> {
|
||||
public String getPreNodeId() {
|
||||
return preNodeId;
|
||||
}
|
||||
}
|
||||
|
||||
public <T extends NodeExecutorConfig> T getConfigObject(Class<T> configClass) {
|
||||
if (configObject == null && config != null) {
|
||||
try {
|
||||
configObject = getObjectMapper().readValue(this.config, configClass);
|
||||
} catch (Exception e) {
|
||||
throw new WorkflowEngineException(ResponseCode.WORKFLOW_NODE_CONFIG_ERROR,
|
||||
String.format("Failed to parse config for node %s: %s", name, e.getMessage()));
|
||||
}
|
||||
}
|
||||
return (T) configObject;
|
||||
}
|
||||
|
||||
public void setConfigObject(NodeExecutorConfig config) {
|
||||
this.configObject = config;
|
||||
try {
|
||||
this.config = getObjectMapper().writeValueAsString(config);
|
||||
} catch (Exception e) {
|
||||
throw new WorkflowEngineException(ResponseCode.WORKFLOW_NODE_CONFIG_ERROR,
|
||||
String.format("Failed to serialize config for node %s: %s", name, e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -161,16 +161,6 @@ public class WorkflowInstance extends Entity<Long> {
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记工作流实例为失败
|
||||
|
||||
Loading…
Reference in New Issue
Block a user