新增:hpc动态命令参数替换逻辑新增
This commit is contained in:
@@ -15,7 +15,7 @@ CREATE TABLE `simulation_job` (
|
||||
`taskName` varchar(255) DEFAULT NULL COMMENT '计算任务所属任务名称',
|
||||
`runId` varchar(64) DEFAULT NULL COMMENT '计算任务所属算力ID',
|
||||
`runName` varchar(255) DEFAULT NULL COMMENT '计算任务所属算力名称',
|
||||
`softwareId` bigint DEFAULT NULL COMMENT '使用软件的id',
|
||||
`softwareId` varchar(128) DEFAULT NULL COMMENT '使用软件的id',
|
||||
`inputFileId` bigint DEFAULT NULL COMMENT '求解文件对应的文件Id',
|
||||
`jobId` varchar(255) DEFAULT NULL COMMENT '计算任务Id,job new 生成',
|
||||
`jobDetailId` varchar(255) DEFAULT NULL COMMENT '计算任务添加时Id,job add 生成',
|
||||
|
||||
94
1-sql/2026-01-09/yang.sql
Normal file
94
1-sql/2026-01-09/yang.sql
Normal file
@@ -0,0 +1,94 @@
|
||||
drop table simulation_soft_config;
|
||||
drop table simulation_command_placeholder;
|
||||
-- 下面的表和app注册表 simulation_app_repository 主键id关联
|
||||
CREATE TABLE `spdm_baseline`.`simulation_hpc_command` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '自增主键',
|
||||
`appUuid` varchar(128) NOT NULL COMMENT 'app注册的uuId',
|
||||
`softName` varchar(255) NOT NULL COMMENT '软件名称,对应的simulation_app_repository的appName,名字建议格式appName_v1',
|
||||
`softVersion` varchar(32) DEFAULT NULL COMMENT '软件版本号',
|
||||
`functionDsc` varchar(255) DEFAULT NULL COMMENT '功能描述(如:电池仿真)',
|
||||
`command` text NOT NULL COMMENT '功能对应的CMD命令',
|
||||
`postFileRegular` varchar(512) DEFAULT NULL COMMENT '预留-软件执行完成后筛选回传文件正则,用于过滤回传文件',
|
||||
`creatorId` bigint DEFAULT NULL COMMENT '创建者ID',
|
||||
`createTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updaterId` bigint DEFAULT NULL COMMENT '更新者ID',
|
||||
`updateTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `simulation_command_soft_name` (`softName`) COMMENT '按软件名称查询',
|
||||
KEY `simulation_command_appUuid` (`appUuid`) COMMENT '按appid查询'
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='仿真软件hpc命令配置表';
|
||||
|
||||
CREATE TABLE `spdm_baseline`.`simulation_hpc_command_placeholder` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '自增主键',
|
||||
`appUuid` varchar(128)NOT NULL COMMENT 'app注册的uuId',
|
||||
`keyEnName` varchar(255) NOT NULL COMMENT '占位符英文名称',
|
||||
`keyCnName` varchar(255) NOT NULL COMMENT '占位符中文名称',
|
||||
`valueType` varchar(50) NOT NULL COMMENT '占位符值的类型(file:共享云盘文件;input:用户自定义输入)',
|
||||
`isDisplay` varchar(1) NOT NULL DEFAULT 'Y' COMMENT '是否展示(Y:是,N:否),N时必须填写默认值',
|
||||
`featchType` varchar(16) NOT NULL DEFAULT 'input' COMMENT '动态参数获取值的来源,input:用户自定义,default:默认值,param:从参数里取',
|
||||
`defaultValue` varchar(512) DEFAULT NULL COMMENT '默认值:valueType为Input且isDisplay为N时必填',
|
||||
`fileRegular` varchar(512) DEFAULT NULL COMMENT '文件正则表达式:valueType为file时必填,用于过滤对应的求解文件',
|
||||
`creatorId` bigint DEFAULT NULL COMMENT '创建者ID',
|
||||
`createTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updaterId` bigint DEFAULT NULL COMMENT '更新者ID',
|
||||
`updateTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `placeholder_appUuid` (`appUuid`) COMMENT 'app表hpc求解器id查询'
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='仿真工具hpc命令占位符配置表';
|
||||
|
||||
-- 记得仿真任务执行的时候也记录 appRepositoryId
|
||||
-- isDisplay 是N 假如 defaultValue是null,则在从提交对象的参数获取数据赋值
|
||||
-- 回传的正则没有就是全部所有的文件
|
||||
-- file类型的,先收集正则,把文件先上传到工作目录
|
||||
|
||||
|
||||
-- job 表修改
|
||||
drop table simulation_job;
|
||||
CREATE TABLE `simulation_job` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID,自增',
|
||||
`jobName` varchar(255) NOT NULL COMMENT '计算任务名称',
|
||||
`coreNum` int DEFAULT NULL COMMENT '计算所需要核数',
|
||||
`software` varchar(100) DEFAULT NULL COMMENT '计算软件的名称',
|
||||
`jobType` varchar(255) DEFAULT NULL COMMENT '计算任务类型',
|
||||
`independence` tinyint(1) NOT NULL DEFAULT '0' COMMENT '计算任务是否独立存在 0:非独立任务 1:独立任务',
|
||||
`inputFiles` text COMMENT '求解文件(JSON格式存储文件UUID列表)',
|
||||
`masterFile` varchar(255) DEFAULT NULL COMMENT '计算主文件(文件UUID)',
|
||||
`taskId` varchar(64) DEFAULT NULL COMMENT '计算任务所属任务ID',
|
||||
`taskName` varchar(255) DEFAULT NULL COMMENT '计算任务所属任务名称',
|
||||
`runId` varchar(64) DEFAULT NULL COMMENT '计算任务所属算力ID',
|
||||
`runName` varchar(255) DEFAULT NULL COMMENT '计算任务所属算力名称',
|
||||
`softwareId` varchar(128) DEFAULT NULL COMMENT '使用软件的uuid',
|
||||
`inputFileId` bigint DEFAULT NULL COMMENT '求解文件对应的文件Id',
|
||||
`jobId` varchar(255) DEFAULT NULL COMMENT '计算任务Id,job new 生成',
|
||||
`jobDetailId` varchar(255) DEFAULT NULL COMMENT '计算任务添加时Id,job add 生成',
|
||||
`stdoutHpcFilePath` varchar(512) DEFAULT NULL COMMENT '任务执行输出的文件在Hpc的绝对路径,共享目录+jobName(文件回传)+uuid,下面可能有多个文件',
|
||||
`stdoutSpdmMinoFilePath` varchar(1024) DEFAULT NULL COMMENT '任务执行输出的文件在 MinIO 上的路径(baseDir+jobName+uuid,可能包含多个文件)',
|
||||
`nodeName` varchar(256) DEFAULT NULL COMMENT '节点名称',
|
||||
`executCommand` text COMMENT '记录最终执行的执行对应工具命令',
|
||||
`startTime` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '任务开始时间',
|
||||
`endTime` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '任务结束时间',
|
||||
`jobStatus` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '' COMMENT '任务状态,spdm,+hpc返回的其他状态(定时任务维护)',
|
||||
`solverName` varchar(200) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '求解器名称',
|
||||
`totalKernelTime` bigint DEFAULT NULL COMMENT '总内核态时间(单位:毫秒)',
|
||||
`totalUserTime` bigint DEFAULT NULL COMMENT '总用户态时间(单位:毫秒)',
|
||||
`totalElapsedTime` bigint DEFAULT NULL COMMENT '作业耗费总秒数(单位:秒)',
|
||||
`uuid` varchar(64) DEFAULT NULL COMMENT '配置提交前端生成不带横线的uuid',
|
||||
`fileStatus` varchar(16) DEFAULT NULL COMMENT '任务结果回传状态,generating,uploading,finished',
|
||||
`creatorId` bigint DEFAULT NULL COMMENT '创建者ID',
|
||||
`createTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updaterId` bigint DEFAULT NULL COMMENT '更新者ID',
|
||||
`updateTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
`stdoutSpdmNasFilePath` varchar(1024) DEFAULT NULL COMMENT '任务执行输出的文件在 NAS 上的路径(baseDir+jobName+uuid,可能包含多个文件)',
|
||||
`tenantId` bigint DEFAULT NULL COMMENT '租户ID',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_task_id` (`taskId`) COMMENT '按所属任务ID查询',
|
||||
KEY `idx_run_id` (`runId`) COMMENT '按所属算力ID查询',
|
||||
KEY `idx_job_name` (`jobName`) COMMENT '按任务名称查询',
|
||||
KEY `idx_job_status` (`jobStatus`) COMMENT '按任务状态查询',
|
||||
KEY `idx_softwareId` (`softwareId`) COMMENT '按软件id查询',
|
||||
KEY `idx_node_name` (`nodeName`) COMMENT '按节点名称查询'
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='仿真计算任务表';
|
||||
|
||||
-- 家里修改
|
||||
-- 修改softwareId字段类型为varchar(128)
|
||||
ALTER TABLE `simulation_job` MODIFY COLUMN `softwareId` varchar(128) DEFAULT NULL COMMENT '使用软件的id';
|
||||
@@ -531,7 +531,7 @@ CREATE TABLE `simulation_job` (
|
||||
`taskName` varchar(255) DEFAULT NULL COMMENT '计算任务所属任务名称',
|
||||
`runId` varchar(64) DEFAULT NULL COMMENT '计算任务所属算力ID',
|
||||
`runName` varchar(255) DEFAULT NULL COMMENT '计算任务所属算力名称',
|
||||
`softwareId` bigint DEFAULT NULL COMMENT '使用软件的id',
|
||||
`softwareId` varchar(128) DEFAULT NULL COMMENT '使用软件的id',
|
||||
`inputFileId` bigint NOT NULL COMMENT '求解文件对应的文件Id',
|
||||
`jobId` varchar(255) DEFAULT NULL COMMENT '计算任务Id,job new 生成',
|
||||
`jobDetailId` varchar(255) DEFAULT NULL COMMENT '计算任务添加时Id,job add 生成',
|
||||
|
||||
@@ -10,7 +10,10 @@ public class HPCExecuteConfig extends BaseExecuteConfig {
|
||||
private String masterFileRegularStr = "^.*\\.xml$";
|
||||
// 先默认写死一个,后面前端配置传递
|
||||
private String inputFilesRegularStr="^.+\\.json$";
|
||||
// 节点的命令
|
||||
// 节点的命令 这个不用传递了,配置在后台表里的
|
||||
private String nodeExeCommand;
|
||||
|
||||
// app注册表的uuid
|
||||
private String uuid;
|
||||
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
public class SubmitHpcTaskRemoteReq implements Serializable {
|
||||
@@ -19,6 +20,9 @@ public class SubmitHpcTaskRemoteReq implements Serializable {
|
||||
@Schema(description = "计算软件")
|
||||
public String software;
|
||||
|
||||
@Schema(description = "计算软件uuid")
|
||||
public String softwareId;
|
||||
|
||||
@Schema(description = "计算任务类型")
|
||||
public String jobType;
|
||||
|
||||
@@ -70,4 +74,7 @@ public class SubmitHpcTaskRemoteReq implements Serializable {
|
||||
@Schema(description = "任务求解文件从文件路径,adapter里使用,executeMode=MANUAL")
|
||||
public List<String> manualInputFilePaths;
|
||||
|
||||
@Schema(description = "任务流用户传递的参数,用于动态替换命令")
|
||||
private Map<String,Object> params;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
package com.sdm.common.utils;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.sdm.common.entity.req.pbs.SubmitHpcTaskRemoteReq;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
@Slf4j
|
||||
public class CommandReplaceUtil {
|
||||
/**
|
||||
* 通用替换方法:将命令字符串中的 %key 占位符替换为指定值
|
||||
* @param command 原始命令字符串(包含%key形式的占位符)
|
||||
* @param key 要替换的占位符键名(不需要带%)
|
||||
* @param value 替换后的值
|
||||
* @return 替换完成后的命令字符串
|
||||
*/
|
||||
public static String replaceCommandPlaceholder(String command, String key, Object value) {
|
||||
// 1. 空值校验,避免空指针异常
|
||||
if (command == null) {
|
||||
throw new IllegalArgumentException("命令字符串(command)不能为null");
|
||||
}
|
||||
if (key == null || key.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("占位符键名(key)不能为null或空字符串");
|
||||
}
|
||||
// value允许为空,空值时直接替换成空字符串
|
||||
String replaceValue = ObjectUtil.isEmpty(value) ? "" : value.toString();
|
||||
|
||||
// 2. 构建要替换的占位符(% + key)
|
||||
String placeholder = "%" + key.trim();
|
||||
|
||||
// 3. 替换所有匹配的占位符
|
||||
return command.replace(placeholder, replaceValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据字段名动态获取对象的字段值
|
||||
* @param obj 目标对象
|
||||
* @param fieldName 字段名(如 masterFileRegularStr)
|
||||
* @return 字段值
|
||||
* @throws NoSuchFieldException 字段不存在
|
||||
* @throws IllegalAccessException 访问权限不足
|
||||
*/
|
||||
public static Object getFieldValue(Object obj, String fieldName) {
|
||||
if (obj == null || fieldName == null || fieldName.isEmpty()) {
|
||||
log.warn("获取对象为空,或者字段名为空");
|
||||
return null;
|
||||
}
|
||||
// 1. 获取对象的Class对象
|
||||
Class<?> clazz = obj.getClass();
|
||||
// 2. 获取字段(包括public/private/protected)
|
||||
Field field = null;
|
||||
try {
|
||||
field = clazz.getDeclaredField(fieldName);
|
||||
} catch (Exception e) {
|
||||
log.warn("反射获取字段{}异常,{}", fieldName,e.getMessage());
|
||||
return null;
|
||||
}
|
||||
// 3. 设置访问权限(即使字段是private也能访问)
|
||||
field.setAccessible(true);
|
||||
// 4. 获取字段值
|
||||
try {
|
||||
Object o = field.get(obj);
|
||||
return o;
|
||||
} catch (Exception e) {
|
||||
log.warn("反射获取字段值{}异常,{}", fieldName,e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// 1. 创建测试对象
|
||||
SubmitHpcTaskRemoteReq req = new SubmitHpcTaskRemoteReq();
|
||||
req.setJobName("流体力学计算");
|
||||
req.setCoreNum(8);
|
||||
req.setMasterFileRegularStr("/data/input/file.txt");
|
||||
req.setSoftwareId("softwareId11");
|
||||
// 获取String类型字段
|
||||
String jobName = (String) getFieldValue(req, "jobName");
|
||||
System.out.println("jobName = " + jobName); // 输出:流体力学计算
|
||||
|
||||
// 获取int类型字段
|
||||
Integer coreNum = (Integer) getFieldValue(req, "coreNum");
|
||||
System.out.println("coreNum = " + coreNum); // 输出:8
|
||||
|
||||
// 获取private字段(appRepositoryId)
|
||||
String appId = (String) getFieldValue(req, "softwareId");
|
||||
System.out.println("softwareId = " + appId); // 输出:1001
|
||||
|
||||
}
|
||||
|
||||
|
||||
// // 测试示例
|
||||
// public static void main(String[] args) {
|
||||
// // 测试用的原始命令
|
||||
// String command = "\\\\CARSAFE\\share\\solver\\RLithium\\reta.exe -i %masterFilePath -t %coreNum -m %memory";
|
||||
// // 替换coreNum为4
|
||||
// String newCommand = replaceCommandPlaceholder(command, "coreNum", "4");
|
||||
// System.out.println("替换后命令:");
|
||||
// System.out.println(newCommand);
|
||||
//
|
||||
// // 继续替换其他占位符示例
|
||||
// newCommand = replaceCommandPlaceholder(newCommand, "memory", "8G");
|
||||
// System.out.println("\n继续替换memory后:");
|
||||
// System.out.println(newCommand);
|
||||
//
|
||||
//
|
||||
// }
|
||||
}
|
||||
@@ -63,7 +63,10 @@ public class HpcHandler implements ExecutionHandler<Map<String, Object>,HPCExecu
|
||||
@Override
|
||||
public void execute(DelegateExecution execution, Map<String, Object> params, HPCExecuteConfig config) {
|
||||
CoreLogger.info("hpc process excute,params:{},config:{}",JSONObject.toJSONString(params),JSONObject.toJSONString(config));
|
||||
SubmitHpcTaskRemoteReq submitHpcTaskRemoteReq = convertParamsToReq(params,config.getNodeExeCommand());
|
||||
SubmitHpcTaskRemoteReq submitHpcTaskRemoteReq = convertParamsToReq(params);
|
||||
submitHpcTaskRemoteReq.setParams(params);
|
||||
// 设置软件id
|
||||
submitHpcTaskRemoteReq.setSoftwareId(config.getUuid());
|
||||
String beforeNodeId = config.getBeforeNodeId();
|
||||
String currentNodeId =execution.getCurrentActivityId();
|
||||
String masterFileRegularStr = config.getMasterFileRegularStr();
|
||||
@@ -89,6 +92,7 @@ public class HpcHandler implements ExecutionHandler<Map<String, Object>,HPCExecu
|
||||
}
|
||||
// 处理hpc求解文件路径
|
||||
dealHpcFile(submitHpcTaskRemoteReq,beforeNodeId,currentNodeId, processDefinitionId,processInstanceId,executeMode,params);
|
||||
//
|
||||
// 实现HPC处理逻辑...
|
||||
// INIT(初始化)/RUNNING(执行中)/SUCCESS(执行成功)/FAIL(执行失败)
|
||||
String status = AsyncTaskStatusEnum.INIT.getCode();
|
||||
@@ -226,10 +230,10 @@ public class HpcHandler implements ExecutionHandler<Map<String, Object>,HPCExecu
|
||||
}
|
||||
|
||||
/**
|
||||
* 将参数Map转换为SubmitHpcTaskRemoteReq对象的工具方法
|
||||
* 将参数Map转换为SubmitHpcTaskRemoteReq对象的工具方法 String command
|
||||
*/
|
||||
private SubmitHpcTaskRemoteReq convertParamsToReq(Map<String, Object> params,String command) {
|
||||
CoreLogger.error("convertParamsToReq start command:{}",command);
|
||||
private SubmitHpcTaskRemoteReq convertParamsToReq(Map<String, Object> params) {
|
||||
CoreLogger.error("convertParamsToReq start ");
|
||||
SubmitHpcTaskRemoteReq req = new SubmitHpcTaskRemoteReq();
|
||||
if (params == null) {
|
||||
return req;
|
||||
@@ -258,14 +262,14 @@ public class HpcHandler implements ExecutionHandler<Map<String, Object>,HPCExecu
|
||||
// String command =(params.get("command")==null||StringUtils.isBlank(params.get("command").toString()))?
|
||||
// "\\\\CARSAFE\\share\\solver\\RLithium\\reta.exe -i %s" : params.get("command").toString();
|
||||
// 只是测试环境用于兜底mock
|
||||
if(StringUtils.isBlank(command)){
|
||||
command = mockCommand;
|
||||
}
|
||||
if(StringUtils.isBlank(command)){
|
||||
CoreLogger.error("command is empty!!!!!");
|
||||
throw new RuntimeException("command is empty");
|
||||
}
|
||||
req.setCommand(command);
|
||||
// if(StringUtils.isBlank(command)){
|
||||
// command = mockCommand;
|
||||
// }
|
||||
// if(StringUtils.isBlank(command)){
|
||||
// CoreLogger.error("command is empty!!!!!");
|
||||
// throw new RuntimeException("command is empty");
|
||||
// }
|
||||
// req.setCommand(command);
|
||||
req.setProjectname(params.get("projectname").toString());
|
||||
// req.setFeatchFileType(params.get("featchFileType").toString());
|
||||
// req.setBeforeNodeId(params.get("beforeNodeId").toString());
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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> {
|
||||
|
||||
}
|
||||
|
||||
@@ -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> {
|
||||
|
||||
}
|
||||
|
||||
11
pbs/src/main/java/com/sdm/pbs/model/bo/CommandResult.java
Normal file
11
pbs/src/main/java/com/sdm/pbs/model/bo/CommandResult.java
Normal 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;
|
||||
}
|
||||
@@ -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_select:Hpc节点文件选择,hpc_file_regex_match:Hpc节点目录正则,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;
|
||||
}
|
||||
@@ -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<>();
|
||||
|
||||
}
|
||||
@@ -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 = "";
|
||||
|
||||
}
|
||||
@@ -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")
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
@@ -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> {
|
||||
}
|
||||
|
||||
@@ -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> {
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
if(Objects.isNull(hpcCommand)){
|
||||
return SdmResponse.failed("该应用未配置hpc命令!");
|
||||
}
|
||||
});
|
||||
config.setCommandExpand(placeholderMap);
|
||||
});
|
||||
// 一个softName --》一个版本--》有多个命令
|
||||
Map<String, List<SimulationSoftConfig>> softConfigs = configs.stream()
|
||||
.collect(Collectors.groupingBy(SimulationSoftConfig::getSoftVersion));
|
||||
return SdmResponse.success(softConfigs);
|
||||
|
||||
for(SimulationHpcCommandPlaceholder placeholder : placeholders){
|
||||
Map<String, Object> commandExpandMap = hpcCommand.getCommandExpand();
|
||||
String keyEnName = placeholder.getKeyEnName();
|
||||
commandExpandMap.put(keyEnName,placeholder);
|
||||
}
|
||||
return SdmResponse.success(hpcCommand);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user