新增:hpc动态命令参数替换逻辑新增

This commit is contained in:
yangyang01000846
2026-01-09 13:56:02 +08:00
parent 2b68984a2b
commit 8e94a46640
22 changed files with 709 additions and 192 deletions

View File

@@ -12,15 +12,11 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
@Slf4j
@@ -35,6 +31,29 @@ public class TaskAdapter implements ITaskFeignClient {
@Autowired
private TaskController taskController;
@Value("${testEnStr:}")
private String enStr;
@Value("${testEnStr2:}")
private String testEnStr2;
@Value("${pbs.task.impl}")
private String pbsImpl;
@GetMapping("/testEn")
@Operation(summary = "作业提交")
public SdmResponse<Map<String,Object>> testEn() {
Map<String, Object> map = new HashMap<>();
map.put("enStr", enStr);
map.put("pbsImpl", pbsImpl);
map.put("testEnStr2", testEnStr2);
return SdmResponse.success(map);
}
@PostMapping("/adapterSubmitHpcJob")
@Operation(summary = "作业提交")
public SdmResponse<String> adapterSubmitHpcJob(@RequestBody SubmitHpcTaskRemoteReq req) {

View File

@@ -14,7 +14,7 @@ import com.sdm.common.utils.HpcCommandExcuteUtil;
import com.sdm.pbs.model.bo.HpcJobStatusInfo;
import com.sdm.pbs.model.bo.HpcResouceInfo;
import com.sdm.pbs.model.entity.SimulationJob;
import com.sdm.pbs.model.entity.SimulationSoftConfig;
import com.sdm.pbs.model.entity.SimulationHpcCommand;
import com.sdm.pbs.model.req.JobFileCallBackReq;
import com.sdm.pbs.model.req.QueryJobReq;
import com.sdm.pbs.model.req.SubmitHpcTaskReq;
@@ -114,8 +114,8 @@ public class TaskController {
@GetMapping("/querySoftConfig")
@Operation(summary = "spdm系统查询hpc求解器指令配置")
SdmResponse<Map<String, List<SimulationSoftConfig>>> querySoftConfig (@RequestParam String softName) {
return pbsServiceDecorator.querySoftConfig(softName);
SdmResponse<SimulationHpcCommand> querySoftConfig (@RequestParam String appUuid) {
return pbsServiceDecorator.querySoftConfig(appUuid);
}

View File

@@ -1,7 +1,7 @@
package com.sdm.pbs.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.sdm.pbs.model.entity.SimulationCommandPlaceholder;
import com.sdm.pbs.model.entity.SimulationHpcCommandPlaceholder;
/**
* <p>
@@ -11,6 +11,6 @@ import com.sdm.pbs.model.entity.SimulationCommandPlaceholder;
* @author author
* @since 2025-11-05
*/
public interface SimulationCommandPlaceholderMapper extends BaseMapper<SimulationCommandPlaceholder> {
public interface SimulationCommandPlaceholderMapper extends BaseMapper<SimulationHpcCommandPlaceholder> {
}

View File

@@ -1,7 +1,7 @@
package com.sdm.pbs.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.sdm.pbs.model.entity.SimulationSoftConfig;
import com.sdm.pbs.model.entity.SimulationHpcCommand;
/**
* <p>
@@ -11,6 +11,6 @@ import com.sdm.pbs.model.entity.SimulationSoftConfig;
* @author author
* @since 2025-11-05
*/
public interface SimulationSoftConfigMapper extends BaseMapper<SimulationSoftConfig> {
public interface SimulationSoftConfigMapper extends BaseMapper<SimulationHpcCommand> {
}

View File

@@ -0,0 +1,11 @@
package com.sdm.pbs.model.bo;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class CommandResult {
private String command;
private String formatCommand;
}

View File

@@ -1,74 +0,0 @@
package com.sdm.pbs.model.entity;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* <p>
* 仿真工具命令占位符配置表
* </p>
*
* @author author
* @since 2025-12-01
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("simulation_command_placeholder")
@Schema(description = "仿真工具命令占位符配置表")
public class SimulationCommandPlaceholder implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "自增主键")
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@Schema(description = "占位符英文名称")
@TableField("keyEnName")
private String keyEnName;
@Schema(description = "占位符中文名称")
@TableField("keyCnName")
private String keyCnName;
@Schema(description = "占位符值的类型file_exact_match:文件完全匹配file_regex_match:文件正则匹配," +
"hpc_file_selectHpc节点文件选择hpc_file_regex_matchHpc节点目录正则local_file_select本地文件选择custom_input用户自定义输入值")
@TableField("valueType")
private String valueType;
@Schema(description = "占位符的值,用户输入后赋值传递")
@TableField(exist = false)
private String inputValue="";
@Schema(description = "创建者ID")
@TableField("creatorId")
@JsonIgnore
private Long creatorId;
@Schema(description = "创建时间")
@TableField(value = "createTime", fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonIgnore
private LocalDateTime createTime;
@Schema(description = "更新者ID")
@TableField("updaterId")
@JsonIgnore
private Long updaterId;
@Schema(description = "修改时间")
@TableField(value = "updateTime", fill = FieldFill.INSERT_UPDATE)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonIgnore
private LocalDateTime updateTime;
}

View File

@@ -2,6 +2,7 @@ package com.sdm.pbs.model.entity;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -9,6 +10,7 @@ import lombok.experimental.Accessors;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
/**
@@ -22,9 +24,9 @@ import java.util.Map;
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("simulation_soft_config")
@Schema(description = "仿真软件命令配置表")
public class SimulationSoftConfig implements Serializable {
@TableName("simulation_hpc_command")
@Schema(description = "仿真软件hpc命令配置表")
public class SimulationHpcCommand implements Serializable {
private static final long serialVersionUID = 1L;
@@ -32,42 +34,55 @@ public class SimulationSoftConfig implements Serializable {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@Schema(description = "软件名称")
@TableField("softName")
@Schema(description = "app注册的Id")
@TableField(value = "appUuid",select = true)
private String appUuid;
@Schema(description = "软件名称,对应的simulation_app_repository的appName名字建议格式appName_v1")
@TableField(value = "softName",select = true)
private String softName;
@Schema(description = "软件版本号")
@TableField("softVersion")
@TableField(value = "softVersion",select = true)
private String softVersion;
@Schema(description = "功能描述(如:电池仿真)")
@TableField("functionDsc")
@TableField(value = "functionDsc",select = true)
private String functionDsc;
@Schema(description = "功能对应的CMD命令")
@TableField("command")
@TableField(value = "command",select = true)
private String command;
@Schema(description = "预留-软件执行完成后筛选回传文件正则,用于过滤回传文件")
@TableField(value = "postFileRegular",select = true)
@JsonIgnore
private String postFileRegular;
@Schema(description = "创建者ID")
@TableField("creatorId")
@TableField(value = "creatorId",select = true)
@JsonIgnore
private Long creatorId;
@Schema(description = "创建时间")
@TableField(value = "createTime", fill = FieldFill.INSERT)
@TableField(value = "createTime", fill = FieldFill.INSERT,select = true)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonIgnore
private LocalDateTime createTime;
@Schema(description = "更新者ID")
@TableField("updaterId")
@TableField(value = "updaterId",select = false)
@JsonIgnore
private Long updaterId;
@Schema(description = "修改时间")
@TableField(value = "updateTime", fill = FieldFill.INSERT_UPDATE)
@TableField(value = "updateTime", fill = FieldFill.INSERT_UPDATE,select = false)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonIgnore
private LocalDateTime updateTime;
@Schema(description= "自定义占位符,只有列表展示使用key 就是占位符")
@TableField(value = "commandExpand", insertStrategy = FieldStrategy.NEVER,select = false,updateStrategy = FieldStrategy.NEVER)
private Map<String,SimulationCommandPlaceholder> commandExpand;
@Schema(description = "命令动态扩展的数据SimulationHpcCommandPlaceholder对象")
@TableField(exist = false)
private Map<String,Object>commandExpand = new HashMap<>();
}

View File

@@ -0,0 +1,99 @@
package com.sdm.pbs.model.entity;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* <p>
* 仿真工具命令占位符配置表
* </p>
*
* @author author
* @since 2025-12-01
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("simulation_hpc_command_placeholder")
@Schema(description = "仿真工具hpc命令占位符配置表")
public class SimulationHpcCommandPlaceholder implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "自增主键")
@TableId(value = "id", type = IdType.AUTO)
@JsonIgnore
private Long id;
@Schema(description = "app注册的Id")
@TableField(value = "appUuid",select = true)
private String appUuid;
@Schema(description = "占位符英文名称")
@TableField(value = "keyEnName",select = true)
private String keyEnName;
@Schema(description = "占位符中文名称")
@TableField(value = "keyCnName",select = true)
private String keyCnName;
@Schema(description = "占位符值的类型file:共享云盘文件input:用户自定义输入)")
@TableField(value = "valueType",select = true)
private String valueType;
@Schema(description = "是否展示Y:是N:否N时必须填写默认值")
@TableField(value = "isDisplay",select = true)
@JsonIgnore
private String isDisplay;
@Schema(description = "是否拼接Y:是N:否N时不用拼接到命令")
@TableField(value = "featchType",select = true)
@JsonIgnore
private String featchType;
@Schema(description = "默认值valueType为file且isDisplay为N时必填")
@TableField(value = "defaultValue",select = true)
@JsonIgnore
private String defaultValue;
@Schema(description = "文件正则表达式valueType为file时必填用于过滤对应的求解文件")
@TableField(value = "fileRegular",select = true)
@JsonIgnore
private String fileRegular;
@Schema(description = "创建者ID")
@TableField(value = "creatorId",select = false)
@JsonIgnore
private Long creatorId;
@Schema(description = "创建时间")
@TableField(value = "createTime", fill = FieldFill.INSERT,select = false)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonIgnore
private LocalDateTime createTime;
@Schema(description = "更新者ID")
@TableField(value = "updaterId",select = false)
@JsonIgnore
private Long updaterId;
@Schema(description = "修改时间")
@TableField(value = "updateTime", fill = FieldFill.INSERT_UPDATE,select = false)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonIgnore
private LocalDateTime updateTime;
@Schema(description = "占位符的值,显示给用户的字段,用户输入后赋值传递")
@TableField(exist = false)
private String inputValue = "";
}

View File

@@ -77,7 +77,7 @@ public class SimulationJob implements Serializable {
@Schema(description = "使用软件的id")
@TableField("softwareId")
private Long softwareId;
private String softwareId;
@Schema(description = "求解文件对应的文件Id")
@TableField("inputFileId")

View File

@@ -7,6 +7,8 @@ import org.springframework.web.multipart.MultipartFile;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Data
public class SubmitHpcTaskReq {
@@ -64,7 +66,7 @@ public class SubmitHpcTaskReq {
public String projectname;
@Schema(description = "软件的id")
public Long softwareId;
public String softwareId;
@Schema(description = "计算任务回传minio的路径")
public String stdoutSpdmMinoFilePath;
@@ -78,5 +80,7 @@ public class SubmitHpcTaskReq {
@Schema(description = "求解文件本地路径,spdm工作流引擎会传递过来")
public List<String> inputFileLocalPaths = new ArrayList<>();
@Schema(description = "任务流用户传递的参数,用于动态替换命令")
private Map<String,Object> params;
}

View File

@@ -1,7 +1,7 @@
package com.sdm.pbs.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.sdm.pbs.model.entity.SimulationCommandPlaceholder;
import com.sdm.pbs.model.entity.SimulationHpcCommandPlaceholder;
public interface ISimulationCommandPlaceholderService extends IService<SimulationCommandPlaceholder> {
public interface ISimulationCommandPlaceholderService extends IService<SimulationHpcCommandPlaceholder> {
}

View File

@@ -1,7 +1,7 @@
package com.sdm.pbs.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.sdm.pbs.model.entity.SimulationSoftConfig;
import com.sdm.pbs.model.entity.SimulationHpcCommand;
public interface ISimulationSoftConfigService extends IService<SimulationSoftConfig> {
public interface ISimulationSoftConfigService extends IService<SimulationHpcCommand> {
}

View File

@@ -2,9 +2,9 @@ package com.sdm.pbs.service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sdm.pbs.dao.SimulationCommandPlaceholderMapper;
import com.sdm.pbs.model.entity.SimulationCommandPlaceholder;
import com.sdm.pbs.model.entity.SimulationHpcCommandPlaceholder;
import org.springframework.stereotype.Service;
@Service
public class SimulationCommandPlaceholderServiceImpl extends ServiceImpl<SimulationCommandPlaceholderMapper, SimulationCommandPlaceholder> implements ISimulationCommandPlaceholderService {
public class SimulationCommandPlaceholderServiceImpl extends ServiceImpl<SimulationCommandPlaceholderMapper, SimulationHpcCommandPlaceholder> implements ISimulationCommandPlaceholderService {
}

View File

@@ -1,5 +1,6 @@
package com.sdm.pbs.service.impl;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
@@ -15,17 +16,20 @@ import com.sdm.common.entity.resp.pbs.hpc.FileNodeInfo;
import com.sdm.common.feign.impl.system.MessageFeignClientImpl;
import com.sdm.common.feign.inter.flowable.IFlowableFeignClient;
import com.sdm.common.log.CoreLogger;
import com.sdm.common.utils.CommandReplaceUtil;
import com.sdm.common.utils.HpcCommandExcuteUtil;
import com.sdm.common.utils.PageUtils;
import com.sdm.pbs.model.bo.CommandResult;
import com.sdm.pbs.model.bo.HpcJobStatusInfo;
import com.sdm.pbs.model.bo.HpcResouceInfo;
import com.sdm.pbs.model.entity.SimulationCommandPlaceholder;
import com.sdm.pbs.model.entity.SimulationHpcCommand;
import com.sdm.pbs.model.entity.SimulationHpcCommandPlaceholder;
import com.sdm.pbs.model.entity.SimulationJob;
import com.sdm.pbs.model.entity.SimulationSoftConfig;
import com.sdm.pbs.model.req.JobFileCallBackReq;
import com.sdm.pbs.model.req.QueryJobReq;
import com.sdm.pbs.model.req.SubmitHpcTaskReq;
import com.sdm.pbs.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
@@ -37,11 +41,14 @@ import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
import java.time.LocalDateTime;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@Slf4j
@Service
@Qualifier("decoratorPbsService")
@ConditionalOnProperty(name = "pbs.task.impl", havingValue = "hpc")
@@ -89,46 +96,139 @@ public class PbsServiceDecorator implements IPbsServiceDecorator {
public SdmResponse<String> submitHpcJob(SubmitHpcTaskReq req) {
//1. 上传hpc主文件 及 其他文件
MultipartFile masterFile = req.getMasterFile();
// hpc共享机器+ subDir 这个就确定是工作目录
String subDir = req.getJobName()+"\\"+System.currentTimeMillis();
// 获取hpc工作目录
String subDir = generateHpcSubDir(req);
// webClient 调用上传这个是主文件求解算出的文件及stdout文件都指定这个文件夹下面
String masterFilePath = hpcCommandExcuteUtil.uploaHpcFile(masterFile,subDir);
dealInputFiles(req,subDir);
String masterFilePath = hpcCommandExcuteUtil.uploaHpcFile(masterFile, subDir);
req.setMasterFilePath(masterFilePath);
// 上传从文件
dealInputFiles(req, subDir);
// 任务输出的文件夹
String hpcOutPutDir = extractDirectory(masterFilePath);
req.setWorkDir(hpcOutPutDir);
// 前置处理 替换求解文件
String command="";
if(StringUtils.isNotBlank(req.getCommand())) {
command=req.getCommand();
}else {
SimulationSoftConfig simulationSoftConfig = simulationSoftConfigService.lambdaQuery().
eq(SimulationSoftConfig::getSoftName,req.getSoftware()).one();
command = simulationSoftConfig.getCommand();
// 2.处理命令拼接和参数替换
CommandResult commandResult = buildAndReplaceHpcCommand(req, masterFilePath);
if (StringUtils.isBlank(commandResult.getCommand())) {
log.error("Hpc执行失败command命令不能为空{}",JSONObject.toJSONString(req));
throw new RuntimeException("Hpc执行失败command命令不能为空");
}
if(StringUtils.isBlank(command)) {
return SdmResponse.failed("command命令不能为空软件名称:"+req.getSoftware());
}
// 处理 拼接命令 \\CARSAFE\share\solver\RLithium\reta.exe -i %s
String formatCommand = String.format(command, masterFilePath);
req.setCommand(formatCommand);
req.setMasterFilePath(masterFilePath);
req.setCommand(commandResult.getFormatCommand());
// 3. 提交
SdmResponse<String> response = pbsService.submitHpcJob(req);
String jobId="";
if(response.isSuccess()&&StringUtils.isNotEmpty(response.getData())) {
String jobId = "";
if (response.isSuccess() && StringUtils.isNotEmpty(response.getData())) {
jobId = response.getData();
}
if(StringUtils.isNotEmpty(jobId)) {
if(StringUtils.isNotEmpty(jobId)){
log.error("Hpc执行失败返回结果{}",JSONObject.toJSONString(response));
throw new RuntimeException("Hpc执行失败返回jobId空");
}
// 4. 保存任务信息到数据库
saveSimulationJobToDb(req, jobId, hpcOutPutDir, commandResult.getCommand());
return SdmResponse.success(jobId);
}
/**
* 生成HPC任务的工作子目录路径简化版
* 目录规则用户ID(非空时)\任务名称\时间戳
* @param req 提交HPC任务的请求参数
* @return 拼接好的子目录字符串
*/
private String generateHpcSubDir(SubmitHpcTaskReq req) {
Long userId = ThreadLocalContext.getUserId();
log.info("Hpc任务执行开始用户id:{}", userId);
// 拼接逻辑
String subDirPrefix = Objects.isNull(userId) ? "" : (String.valueOf(userId) + "\\");
String subDir = subDirPrefix + req.getJobName() + "\\" + System.currentTimeMillis();
return subDir;
}
/**
* 构建并替换HPC命令中的动态参数
* @param req 任务请求参数
* @param masterFilePath 主文件路径
* @return 包含原始命令和格式化命令的结果对象
*/
private CommandResult buildAndReplaceHpcCommand(SubmitHpcTaskReq req, String masterFilePath) {
String command = "";
String formatCommand = "";
// 优先使用传递的command,然后替换求解文件即可
if (StringUtils.isNotBlank(req.getCommand())) {
command = req.getCommand();
// 处理 拼接命令 \\CARSAFE\share\solver\RLithium\reta.exe -i %s
formatCommand = String.format(command, masterFilePath);
} else {
// 命令
SimulationHpcCommand simulationHpcCommand = simulationSoftConfigService.lambdaQuery()
.eq(SimulationHpcCommand::getAppUuid, req.getSoftwareId()).one();
// 动态参数
List<SimulationHpcCommandPlaceholder> placeholders = simulationCommandPlaceholderService.lambdaQuery()
.eq(SimulationHpcCommandPlaceholder::getAppUuid, req.getSoftwareId())
.list();
// 配置在表中的包含动态参数的命令
if (ObjectUtil.isNull(simulationHpcCommand) || StringUtils.isBlank(simulationHpcCommand.getCommand())) {
throw new RuntimeException("该应用没有初始化配置command");
}
command = simulationHpcCommand.getCommand();
// 命令中动态参数的处理替换
for (SimulationHpcCommandPlaceholder placeholder : placeholders) {
String keyEnName = placeholder.getKeyEnName();
Object replaceValue = null;
// 用户手动输入
if (Objects.equals(placeholder.getFeatchType(), "input")) {
replaceValue = req.getParams().get(keyEnName);
// 用户输入是空就使用配置的默认值
if (ObjectUtil.isNull(replaceValue)) { // 修复原代码的判断逻辑错误
log.warn("Hpc命令动态参数替换用户输入是空参数名{}", keyEnName);
replaceValue = placeholder.getDefaultValue();
}
}
// 入参
else if (Objects.equals(placeholder.getFeatchType(), "param")) {
replaceValue = CommandReplaceUtil.getFieldValue(req, keyEnName);
if (ObjectUtil.isNull(replaceValue)) { // 修复原代码的判断逻辑错误
log.warn("Hpc命令动态参数替换入参反射是空参数名{}", keyEnName);
replaceValue = placeholder.getDefaultValue();
}
}
// 默认兜底,比如从文件 就是null,最后命令就不拼接从文件
else if (Objects.equals(placeholder.getFeatchType(), "default")) {
replaceValue = placeholder.getDefaultValue();
if (ObjectUtil.isNull(replaceValue)) { // 修复原代码的判断逻辑错误
log.warn("Hpc命令动态参数替换默认值是空参数名{}", keyEnName);
}
}
command = CommandReplaceUtil.replaceCommandPlaceholder(command, keyEnName, replaceValue);
}
}
return new CommandResult(command, formatCommand);
}
/**
* 保存模拟任务信息到数据库
* @param req 任务请求参数
* @param jobId 任务ID
* @param hpcOutPutDir 输出目录
* @param command 执行命令
*/
private void saveSimulationJobToDb(SubmitHpcTaskReq req, String jobId, String hpcOutPutDir, String command) {
if (StringUtils.isNotEmpty(jobId)) {
// 数据入库
SimulationJob simulationJob = new SimulationJob();
// 基础字段
// simulationJob.setId(1L);
// simulationJob.setId(1L);
simulationJob.setJobName(req.getJobName());
simulationJob.setCoreNum(req.getCoreNum());
simulationJob.setSoftware(req.getSoftware());
simulationJob.setJobType(req.getJobType());
simulationJob.setIndependence(req.isIndependence());
// simulationJob.setInputFiles(JSONObject.toJSONString(req.getInputFiles()));
// simulationJob.setInputFiles(JSONObject.toJSONString(req.getInputFiles()));
// 主文件位置
simulationJob.setMasterFile(req.getMasterFilePath());
// 求解文件集合
@@ -140,20 +240,20 @@ public class PbsServiceDecorator implements IPbsServiceDecorator {
// 软件及文件关联
simulationJob.setSoftwareId(req.getSoftwareId());
// 下面的待定
// simulationJob.setInputFileId(null);
// simulationJob.setInputFileId(null);
simulationJob.setJobId(jobId);
// 没必要要
// simulationJob.setJobDetailId("");
// simulationJob.setJobDetailId("");
// 文件路径 共享目录+jobName文件回传)+uuid下面可能有多个文件
simulationJob.setStdoutHpcFilePath(hpcOutPutDir);
simulationJob.setStdoutSpdmMinoFilePath(req.getStdoutSpdmMinoFilePath());
simulationJob.setStdoutSpdmNasFilePath(req.getStdoutSpdmNasFilePath());
// 执行信息 定时任务回传的时候修改
// simulationJob.setNodeName("");
// simulationJob.setNodeName("");
simulationJob.setExecutCommand(command);
// 执行信息 定时任务回传的时候修改
// simulationJob.setStartTime("2025-11-30 10:00:00");
// simulationJob.setEndTime("2025-11-30 12:30:00");
// simulationJob.setStartTime("2025-11-30 10:00:00");
// simulationJob.setEndTime("2025-11-30 12:30:00");
simulationJob.setJobStatus("Configuring");
// 求解器名称
simulationJob.setSolverName(req.getSoftware());
@@ -162,12 +262,12 @@ public class PbsServiceDecorator implements IPbsServiceDecorator {
simulationJob.setTotalUserTime(null);
simulationJob.setTotalElapsedTime(null);
// 标识及状态
// simulationJob.setUuid(null);
// simulationJob.setUuid(null);
simulationJob.setFileStatus("generating");
// 审计字段
Long userId = ThreadLocalContext.getUserId();
Long tenantId = ThreadLocalContext.getTenantId();
CoreLogger.info("submitHpcJob save db userId:{},tenantId:{}",userId,tenantId);
CoreLogger.info("submitHpcJob save db userId:{},tenantId:{}", userId, tenantId);
simulationJob.setCreatorId(userId);
simulationJob.setTenantId(tenantId);
simulationJob.setCreateTime(LocalDateTime.now());
@@ -175,9 +275,147 @@ public class PbsServiceDecorator implements IPbsServiceDecorator {
simulationJob.setUpdateTime(LocalDateTime.now());
simulationJobService.save(simulationJob);
}
return SdmResponse.success(jobId);
}
// @Override
// public SdmResponse<String> submitHpcJob(SubmitHpcTaskReq req) {
// //1. 上传hpc主文件 及 其他文件
// MultipartFile masterFile = req.getMasterFile();
// // hpc共享机器+ subDir 这个就确定是工作目录了 todo 加上用户目录
// String subDir = req.getJobName()+"\\"+System.currentTimeMillis();
// // webClient 调用上传这个是主文件求解算出的文件及stdout文件都指定这个文件夹下面
// String masterFilePath = hpcCommandExcuteUtil.uploaHpcFile(masterFile,subDir);
// req.setMasterFilePath(masterFilePath);
// // 上传从文件
// dealInputFiles(req,subDir);
// // 任务输出的文件夹
// String hpcOutPutDir = extractDirectory(masterFilePath);
// req.setWorkDir(hpcOutPutDir);
// // 前置处理 替换求解文件
// String command="";
// String formatCommand="";
// // 优先使用传递的command,然后替换求解文件即可
// if(StringUtils.isNotBlank(req.getCommand())) {
// command=req.getCommand();
// // 处理 拼接命令 \\CARSAFE\share\solver\RLithium\reta.exe -i %s
// formatCommand = String.format(command, masterFilePath);
// }else {
// // 命令
// SimulationHpcCommand simulationHpcCommand = simulationSoftConfigService.lambdaQuery().
// eq(SimulationHpcCommand::getAppRepositoryId,req.getAppRepositoryId()).one();
// // 动态参数
// List<SimulationHpcCommandPlaceholder> placeholders = simulationCommandPlaceholderService.lambdaQuery()
// .eq(SimulationHpcCommandPlaceholder::getAppRepositoryId, req.getAppRepositoryId())
// .list();
// // 配置在表中的包含动态参数的命令
// if(ObjectUtil.isNull(simulationHpcCommand)||StringUtils.isBlank(simulationHpcCommand.getCommand())) {
// throw new RuntimeException("该应用没有初始化配置command");
// }
// command = simulationHpcCommand.getCommand();
// // 命令中动态参数的处理替换
// for(SimulationHpcCommandPlaceholder placeholder : placeholders) {
// String keyEnName = placeholder.getKeyEnName();
// // 用户手动输入
// if(Objects.equals(placeholder.getFeatchType(),"input")) {
// Object value = req.getParams().get(keyEnName);
// // 用户输入是空就使用配置的默认值
// if(ObjectUtil.isNotNull(value)) {
// log.warn("Hpc命令动态参数替换用户输入是空参数名{}",keyEnName);
// value=placeholder.getDefaultValue();
// }
// command = CommandReplaceUtil.replaceCommandPlaceholder(command, keyEnName, value);
// }
// // 入参
// if(Objects.equals(placeholder.getFeatchType(),"param")) {
// Object fieldValue = CommandReplaceUtil.getFieldValue(req, keyEnName);
// if(ObjectUtil.isNotNull(fieldValue)) {
// log.warn("Hpc命令动态参数替换入参反射是空参数名{}",keyEnName);
// fieldValue=placeholder.getDefaultValue();
// }
// command = CommandReplaceUtil.replaceCommandPlaceholder(command, keyEnName, fieldValue);
// }
// // 默认兜底,比如从文件 就是null,最后命令就不拼接从文件
// if(Objects.equals(placeholder.getFeatchType(),"default")) {
// Object defaultValue = placeholder.getDefaultValue();
// if(ObjectUtil.isNotNull(defaultValue)) {
// log.warn("Hpc命令动态参数替换默认值是空参数名{}",keyEnName);
// }
// command = CommandReplaceUtil.replaceCommandPlaceholder(command, keyEnName, defaultValue);
// }
//
// }
// }
//
// if(StringUtils.isBlank(command)) {
// return SdmResponse.failed("command命令不能为空软件名称:"+req.getSoftware());
// }
//
// req.setCommand(formatCommand);
// SdmResponse<String> response = pbsService.submitHpcJob(req);
// String jobId="";
// if(response.isSuccess()&&StringUtils.isNotEmpty(response.getData())) {
// jobId = response.getData();
// }
// if(StringUtils.isNotEmpty(jobId)) {
// // 数据入库
// SimulationJob simulationJob = new SimulationJob();
// // 基础字段
//// simulationJob.setId(1L);
// simulationJob.setJobName(req.getJobName());
// simulationJob.setCoreNum(req.getCoreNum());
// simulationJob.setSoftware(req.getSoftware());
// simulationJob.setJobType(req.getJobType());
// simulationJob.setIndependence(req.isIndependence());
//// simulationJob.setInputFiles(JSONObject.toJSONString(req.getInputFiles()));
// // 主文件位置
// simulationJob.setMasterFile(req.getMasterFilePath());
// // 求解文件集合
// simulationJob.setInputFiles(JSONObject.toJSONString(req.getInputFilePaths()));
// simulationJob.setTaskId(req.getTaskId());
// simulationJob.setTaskName(req.getTaskName());
// simulationJob.setRunId(req.getRunId());
// simulationJob.setRunName(req.getRunName());
// // 软件及文件关联
// simulationJob.setSoftwareId(req.getSoftwareId());
// // 下面的待定
//// simulationJob.setInputFileId(null);
// simulationJob.setJobId(jobId);
// // 没必要要
//// simulationJob.setJobDetailId("");
// // 文件路径 共享目录+jobName文件回传)+uuid下面可能有多个文件
// simulationJob.setStdoutHpcFilePath(hpcOutPutDir);
// simulationJob.setStdoutSpdmMinoFilePath(req.getStdoutSpdmMinoFilePath());
// simulationJob.setStdoutSpdmNasFilePath(req.getStdoutSpdmNasFilePath());
// // 执行信息 定时任务回传的时候修改
//// simulationJob.setNodeName("");
// simulationJob.setExecutCommand(command);
// // 执行信息 定时任务回传的时候修改
//// simulationJob.setStartTime("2025-11-30 10:00:00");
//// simulationJob.setEndTime("2025-11-30 12:30:00");
// simulationJob.setJobStatus("Configuring");
// // 求解器名称
// simulationJob.setSolverName(req.getSoftware());
// // 执行信息 定时任务回传的时候修改
// simulationJob.setTotalKernelTime(null);
// simulationJob.setTotalUserTime(null);
// simulationJob.setTotalElapsedTime(null);
// // 标识及状态
//// simulationJob.setUuid(null);
// simulationJob.setFileStatus("generating");
// // 审计字段
// Long userId = ThreadLocalContext.getUserId();
// Long tenantId = ThreadLocalContext.getTenantId();
// CoreLogger.info("submitHpcJob save db userId:{},tenantId:{}",userId,tenantId);
// simulationJob.setCreatorId(userId);
// simulationJob.setTenantId(tenantId);
// simulationJob.setCreateTime(LocalDateTime.now());
// simulationJob.setUpdaterId(userId);
// simulationJob.setUpdateTime(LocalDateTime.now());
// simulationJobService.save(simulationJob);
// }
// return SdmResponse.success(jobId);
// }
private void dealInputFiles(SubmitHpcTaskReq req, String subDir) {
if(req.getInputFiles()==null|| CollectionUtils.isEmpty(req.getInputFiles())) {
return;
@@ -276,35 +514,24 @@ public class PbsServiceDecorator implements IPbsServiceDecorator {
return PageUtils.getJsonObjectSdmResponse(results, page);
}
public SdmResponse<Map<String, List<SimulationSoftConfig>>> querySoftConfig(String softName) {
List<SimulationSoftConfig> configs = simulationSoftConfigService.lambdaQuery()
.eq(SimulationSoftConfig::getSoftName, softName)
.orderByDesc(SimulationSoftConfig::getCreateTime)
public SdmResponse<SimulationHpcCommand> querySoftConfig(String appUuid) {
// app对应hpc命令,一个只会有一个
SimulationHpcCommand hpcCommand = simulationSoftConfigService.lambdaQuery()
.eq(SimulationHpcCommand::getAppUuid, appUuid).one();
// 查询显示用户的动态参数
List<SimulationHpcCommandPlaceholder> placeholders = simulationCommandPlaceholderService.lambdaQuery()
.eq(SimulationHpcCommandPlaceholder::getAppUuid, appUuid)
.eq(SimulationHpcCommandPlaceholder::getValueType,"input")
.list();
List<SimulationCommandPlaceholder> placeholders = simulationCommandPlaceholderService.lambdaQuery().list();
Map<String, SimulationCommandPlaceholder> placeholderMap = placeholders.stream()
.collect(Collectors.toMap(
SimulationCommandPlaceholder::getKeyEnName, // 键keyEnName
placeholder -> placeholder,
(existing, replacement) -> existing
));
configs.forEach(config -> {
HashMap<String, SimulationCommandPlaceholder> map = new HashMap<>();
String command = config.getCommand();
List<String> placeholderKeys = extractPlaceholders(command);
placeholderKeys.stream().forEach(placeholderKey -> {
SimulationCommandPlaceholder simulationCommandPlaceholder = placeholderMap.get(placeholderKey);
if (simulationCommandPlaceholder != null) {
map.put(placeholderKey, simulationCommandPlaceholder);
}
});
config.setCommandExpand(placeholderMap);
});
// 一个softName --》一个版本--》有多个命令
Map<String, List<SimulationSoftConfig>> softConfigs = configs.stream()
.collect(Collectors.groupingBy(SimulationSoftConfig::getSoftVersion));
return SdmResponse.success(softConfigs);
if(Objects.isNull(hpcCommand)){
return SdmResponse.failed("该应用未配置hpc命令");
}
for(SimulationHpcCommandPlaceholder placeholder : placeholders){
Map<String, Object> commandExpandMap = hpcCommand.getCommandExpand();
String keyEnName = placeholder.getKeyEnName();
commandExpandMap.put(keyEnName,placeholder);
}
return SdmResponse.success(hpcCommand);
}
/**

View File

@@ -2,10 +2,10 @@ package com.sdm.pbs.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sdm.pbs.dao.SimulationSoftConfigMapper;
import com.sdm.pbs.model.entity.SimulationSoftConfig;
import com.sdm.pbs.model.entity.SimulationHpcCommand;
import com.sdm.pbs.service.ISimulationSoftConfigService;
import org.springframework.stereotype.Service;
@Service
public class SimulationSoftConfigServiceImpl extends ServiceImpl<SimulationSoftConfigMapper, SimulationSoftConfig> implements ISimulationSoftConfigService {
public class SimulationSoftConfigServiceImpl extends ServiceImpl<SimulationSoftConfigMapper, SimulationHpcCommand> implements ISimulationSoftConfigService {
}