|
@@ -1,9 +1,21 @@
|
|
|
package com.css.simulation.resource.scheduler.app.service;
|
|
|
|
|
|
import api.common.pojo.constants.DictConstants;
|
|
|
+import api.common.pojo.enums.MultiSimulationStatusEnum;
|
|
|
+import api.common.pojo.param.project.MultiCreateYamlRet;
|
|
|
+import api.common.pojo.param.project.MultiSimulationProjectKafkaParam;
|
|
|
+import api.common.pojo.param.project.MultiSimulationProjectParam;
|
|
|
+import api.common.pojo.param.project.MultiSimulationSceneKafkaParam;
|
|
|
+import api.common.pojo.po.project.MultiSimulationProjectTaskRecordPO;
|
|
|
+import api.common.pojo.vo.map.SimulationMapVO;
|
|
|
+import api.common.pojo.vo.project.MultiSimulationProjectVO;
|
|
|
+import api.common.pojo.vo.project.MultiSimulationSceneCarVO;
|
|
|
import api.common.util.*;
|
|
|
+import com.alibaba.fastjson.JSONArray;
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
import com.css.simulation.resource.scheduler.adapter.entity.ProjectStartMessageEntity;
|
|
|
import com.css.simulation.resource.scheduler.adapter.entity.ProjectStopMessageEntity;
|
|
|
+import com.css.simulation.resource.scheduler.app.entity.MultiProjectWaitQueueEntity;
|
|
|
import com.css.simulation.resource.scheduler.app.entity.ProjectWaitQueueEntity;
|
|
|
import com.css.simulation.resource.scheduler.app.entity.VehicleEntity;
|
|
|
import com.css.simulation.resource.scheduler.domain.service.ProjectDomainService;
|
|
@@ -34,6 +46,8 @@ import org.springframework.kafka.core.KafkaTemplate;
|
|
|
import org.springframework.kafka.support.SendResult;
|
|
|
import org.springframework.scheduling.annotation.Async;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+import org.springframework.util.CollectionUtils;
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
|
import java.io.File;
|
|
@@ -52,6 +66,11 @@ public class ProjectApplicationService {
|
|
|
private String linuxTempPath;
|
|
|
@Value("${scheduler.linux-path.pod-yaml-directory}")
|
|
|
private String podYamlDirectory;
|
|
|
+
|
|
|
+ @Value("${scheduler.linux-path.multi-pod-yaml-directory}")
|
|
|
+ private String multiPodYamlDirectory;
|
|
|
+ @Value("${scheduler.linux-path.multi-vtd-xml-generator}")
|
|
|
+ private String multiVtdXmlGenerator;
|
|
|
@Value("${minio.bucket-name}")
|
|
|
private String bucketName;
|
|
|
|
|
@@ -100,6 +119,17 @@ public class ProjectApplicationService {
|
|
|
private CustomRedisClient customRedisClient;
|
|
|
@Resource
|
|
|
private AlgorithmExpandMapper algorithmExpandMapper;
|
|
|
+ @Resource
|
|
|
+ private SimulationMapMapper mapMapper;
|
|
|
+ @Resource
|
|
|
+ private MultiSimulationSceneCarMapper sceneCarMapper;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private MultiSimulationProjectMapper multiSimulationProjectMapper;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private MultiSimulationProjectTaskRecordMapper taskRecordMapper;
|
|
|
+
|
|
|
|
|
|
// -------------------------------- Comment --------------------------------
|
|
|
|
|
@@ -475,6 +505,123 @@ public class ProjectApplicationService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ public void waitMulti(MultiProjectWaitQueueEntity multiProjectWaitQueue) {
|
|
|
+ try {
|
|
|
+ //2 创建等待列表对象
|
|
|
+ final String waitingQueueJson = customRedisClient.get(DictConstants.MULTI_PROJECT_WAIT_QUEUE_KEY);
|
|
|
+ List<MultiProjectWaitQueueEntity> waitingQueue;
|
|
|
+ if (StringUtil.isEmpty(waitingQueueJson)) {
|
|
|
+ waitingQueue = new ArrayList<>();
|
|
|
+ } else {
|
|
|
+ waitingQueue = JsonUtil.jsonToList(waitingQueueJson, MultiProjectWaitQueueEntity.class);
|
|
|
+ }
|
|
|
+ boolean contains = false;
|
|
|
+ for (MultiProjectWaitQueueEntity waitQueueEntity : waitingQueue) {
|
|
|
+ if (waitQueueEntity.getProjectId().equals(multiProjectWaitQueue.getProjectId())) {
|
|
|
+ contains = true;
|
|
|
+ if (multiProjectWaitQueue.getWaitingParallelism() > 0){
|
|
|
+ waitQueueEntity.setWaitingParallelism(multiProjectWaitQueue.getWaitingParallelism());
|
|
|
+ waitQueueEntity.setMultiTaskMessageEntityList(multiProjectWaitQueue.getMultiTaskMessageEntityList());
|
|
|
+ waitQueueEntity.setRunState(multiProjectWaitQueue.getRunState());
|
|
|
+ }else {
|
|
|
+ // 项目等待为0,则删除
|
|
|
+ waitingQueue.remove(waitQueueEntity);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!contains) {
|
|
|
+ waitingQueue.add(multiProjectWaitQueue);
|
|
|
+ }
|
|
|
+ String newWaitingQueueJson = JsonUtil.listToJson(waitingQueue);
|
|
|
+ customRedisClient.set(DictConstants.MULTI_PROJECT_WAIT_QUEUE_KEY, newWaitingQueueJson);
|
|
|
+ } catch (JsonProcessingException e) {
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void removeMulti(String projectId) {
|
|
|
+ try {
|
|
|
+ //2 创建等待列表对象
|
|
|
+ final String waitingQueueJson = customRedisClient.get(DictConstants.MULTI_PROJECT_WAIT_QUEUE_KEY);
|
|
|
+ List<MultiProjectWaitQueueEntity> waitingQueue;
|
|
|
+ if (StringUtil.isEmpty(waitingQueueJson)) {
|
|
|
+ waitingQueue = new ArrayList<>();
|
|
|
+ } else {
|
|
|
+ waitingQueue = JsonUtil.jsonToList(waitingQueueJson, MultiProjectWaitQueueEntity.class);
|
|
|
+ }
|
|
|
+ for (MultiProjectWaitQueueEntity waitQueueEntity : waitingQueue) {
|
|
|
+ if (waitQueueEntity.getProjectId().equals(projectId)) {
|
|
|
+ waitingQueue.remove(waitQueueEntity);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ String newWaitingQueueJson = JsonUtil.listToJson(waitingQueue);
|
|
|
+ customRedisClient.set(DictConstants.MULTI_PROJECT_WAIT_QUEUE_KEY, newWaitingQueueJson);
|
|
|
+ } catch (JsonProcessingException e) {
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @SneakyThrows
|
|
|
+ public void runMulti(int parallelism, MultiProjectWaitQueueEntity multiProjectWaitQueue, String isChoiceGpu) {
|
|
|
+ // 然后再判断是否执行完,未执行完的话则塞入redis,执行完则删除redis
|
|
|
+ // 启动成功之后,更新mysql
|
|
|
+ List<MultiTaskMessageEntity> multiTaskMessageEntityList = multiProjectWaitQueue.getMultiTaskMessageEntityList();
|
|
|
+ String projectId = multiProjectWaitQueue.getProjectId();
|
|
|
+
|
|
|
+ int parallel = parallelism;
|
|
|
+ if (multiTaskMessageEntityList.size()- multiProjectWaitQueue.getRunState()-1 < parallelism){
|
|
|
+ log.info("出现奇怪情况需要使用的并行度大于剩余任务数量parallelism:{},projectId:{},剩余:{}", parallelism, projectId, JSONObject.toJSONString(multiProjectWaitQueue));
|
|
|
+ parallel = multiTaskMessageEntityList.size();
|
|
|
+ }
|
|
|
+ Integer runState = multiProjectWaitQueue.getRunState();
|
|
|
+ // 使用完塞入
|
|
|
+ Map<String, Integer> multiNodeMapToUse = projectDomainService.getMultiNodeMapToUse(isChoiceGpu, parallel);
|
|
|
+ List<MultiCreateYamlRet> yamlList = new ArrayList<>();
|
|
|
+ for (int i = runState + 1; i < parallel + runState + 1; i++) {
|
|
|
+ MultiTaskMessageEntity messageEntity = multiTaskMessageEntityList.get(i);
|
|
|
+ String taskId = messageEntity.getInfo().getTask_id();
|
|
|
+ // 发送kafka消息
|
|
|
+ SendResult<String, String> stringStringSendResult = kafkaTemplate.send(projectId, i % multiTaskMessageEntityList.size(),
|
|
|
+ taskId, JSONObject.toJSONString(messageEntity)).get();
|
|
|
+ RecordMetadata recordMetadata = stringStringSendResult.getRecordMetadata();
|
|
|
+ String topic = recordMetadata.topic(); // 消息发送到的topic
|
|
|
+ int partition = recordMetadata.partition(); // 消息发送到的分区
|
|
|
+ long offset = recordMetadata.offset(); // 消息在分区内的offset
|
|
|
+ log.info("多模式仿真任务发送消息成功, 主题 topic 为项目ID:" + topic + " 分区 partition 为:" + partition + " 偏移量为:" + offset);
|
|
|
+// String sceneId = messageEntity.getInfo().getScene_id();
|
|
|
+ String modelName =null;
|
|
|
+ for (String name: multiNodeMapToUse.keySet()) {
|
|
|
+ Integer integer = multiNodeMapToUse.get(name);
|
|
|
+ if (integer > 0){
|
|
|
+ modelName = name;
|
|
|
+ multiNodeMapToUse.put(name, integer -1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (modelName == null){
|
|
|
+ throw new RuntimeException("未选取到可用的节点");
|
|
|
+ }
|
|
|
+ MultiSimulationSceneKafkaParam multiSimulationSceneKafkaParam = multiProjectWaitQueue.getKafkaParamList().get(i);
|
|
|
+ MultiCreateYamlRet multiTempYaml = projectDomainService.createMultiTempYaml(projectId, multiSimulationSceneKafkaParam, messageEntity, modelName, partition, offset, isChoiceGpu);
|
|
|
+ multiTempYaml.setTaskId(messageEntity.getInfo().getTask_id());
|
|
|
+ multiTempYaml.setNodeName(modelName);
|
|
|
+ yamlList.add(multiTempYaml);
|
|
|
+ }
|
|
|
+ TimeUnit.SECONDS.sleep(10);
|
|
|
+ log.info("项目" + projectId + "共发送了" + yamlList.size() + "条消息,准备首先启动" + yamlList);
|
|
|
+ for (MultiCreateYamlRet redisKey : yamlList) {
|
|
|
+ projectDomainService.createMultiPodBegin(redisKey, redisKey.getYamlRedisKey());
|
|
|
+ // 存nodeName
|
|
|
+ stringRedisTemplate.opsForValue().set("multi-taskId:" + redisKey.getTaskId(), JSONObject.toJSONString(redisKey));
|
|
|
+ // 并行度减1
|
|
|
+ projectDomainService.decrementParallelism(isChoiceGpu, redisKey.getNodeName(), 1);
|
|
|
+ }
|
|
|
+ log.info("项目" + projectId + "已经启动" + yamlList.size());
|
|
|
+ for (MultiCreateYamlRet redisKey : yamlList) {
|
|
|
+ taskRecordMapper.updateMultiSimulationProjectTaskRecordStatus(MultiSimulationStatusEnum.RUN_STATUS.getProjectStatus(), redisKey.getTaskId(), 0);
|
|
|
+ }
|
|
|
+ // 保存每个机器的并行度
|
|
|
+ projectDomainService.setMultiNodeMapUse(isChoiceGpu, multiNodeMapToUse);
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* 运行项目
|
|
@@ -875,5 +1022,301 @@ public class ProjectApplicationService {
|
|
|
projectDomainService.checkAlgorithmIsExpand(projectType, projectId, DictConstants.ALGORITHM_EXPAND_STATUS_NOT_TESTED);
|
|
|
}
|
|
|
|
|
|
+ @Async("pool1")
|
|
|
+ public void runMultiProject(MultiSimulationProjectKafkaParam projectStartMessageEntity) {
|
|
|
+ MultiProjectWaitQueueEntity multiTaskAndFixData = createMultiTaskAndFixData(projectStartMessageEntity);
|
|
|
+ checkIfCanRunMulti(multiTaskAndFixData);
|
|
|
+ }
|
|
|
+ @SneakyThrows
|
|
|
+// @Transactional
|
|
|
+ public void stopMultiProject(MultiSimulationProjectKafkaParam projectKafkaParam) {
|
|
|
+ String projectId = projectKafkaParam.getProjectId();
|
|
|
+ // 删除等待队列中的项目,,
|
|
|
+ removeMulti(projectId);
|
|
|
+ String isChoiceGpu = DictConstants.USE_GPU;
|
|
|
+
|
|
|
+ MultiSimulationProjectVO projectVO = multiSimulationProjectMapper.selectMultiSimulationProjectById(projectId);
|
|
|
+ Integer status = projectVO.getProjectStatus();
|
|
|
+ MultiSimulationProjectParam multiSimulationProjectParam = new MultiSimulationProjectParam();
|
|
|
+ multiSimulationProjectParam.setProjectId(projectId);
|
|
|
+ String projectUserId = projectVO.getProjectUserId();
|
|
|
+ String clusterUserId = projectDomainService.getClusterUserIdByProjectUserId(projectUserId);
|
|
|
+
|
|
|
+ // 查看mysql项目是否已经运行
|
|
|
+ // 如果不为空,则代表已经执行,为空则代表kafka还未被消费
|
|
|
+ List<MultiSimulationProjectTaskRecordPO> recordPOList = taskRecordMapper.selectMultiSimulationProjectTaskRecordList(projectId);
|
|
|
+ if (!CollectionUtils.isEmpty(recordPOList)){
|
|
|
+ for (MultiSimulationProjectTaskRecordPO po: recordPOList) {
|
|
|
+ Integer recordStatus = po.getStatus();
|
|
|
+ if (recordStatus == MultiSimulationStatusEnum.RUN_STATUS.getProjectStatus()){
|
|
|
+ taskRecordMapper.updateMultiSimulationProjectTaskRecordStatus(MultiSimulationStatusEnum.TERMINATED_STATUS.getProjectStatus(), po.getId(), 1);
|
|
|
+ // 删除pod
|
|
|
+ String nodeNameKey = "multi-taskId:" + po.getId();
|
|
|
+ String value = stringRedisTemplate.opsForValue().get(nodeNameKey);
|
|
|
+ MultiCreateYamlRet multiCreateYamlRet = JSONObject.parseObject(value, MultiCreateYamlRet.class);
|
|
|
+
|
|
|
+ String nodeName = multiCreateYamlRet.getNodeName();
|
|
|
+ String podName = multiCreateYamlRet.getPodName();
|
|
|
+ // 删除 pod
|
|
|
+ projectDomainService.deleteMultiProjectPod(podName);
|
|
|
+ // 节点并行度加一
|
|
|
+ projectDomainService.incrementOneParallelism(isChoiceGpu, nodeName);
|
|
|
+ // 释放证书
|
|
|
+ projectDomainService.releaseLicense(clusterUserId, DictConstants.MODEL_TYPE_VTD, 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 设置整个仿真项目
|
|
|
+ if (status == MultiSimulationStatusEnum.RUN_STATUS.getProjectStatus()){
|
|
|
+ multiSimulationProjectParam.setProjectStatus(MultiSimulationStatusEnum.TERMINATED_STATUS.getProjectStatus());
|
|
|
+ multiSimulationProjectMapper.updateMultiSimulationProjectStatus(multiSimulationProjectParam);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 删除kafka topic
|
|
|
+ KafkaUtil.deleteTopic(kafkaAdminClient, projectId);
|
|
|
+ //6 删除项目 pod 启动文件
|
|
|
+ FileUtil.deleteFileBySubstring(multiPodYamlDirectory, projectId);
|
|
|
+ //7 删除项目临时文件
|
|
|
+ FileUtil.rm(linuxTempPath + "multiProject/" + projectId + "/");
|
|
|
+ // 删除minio临时文件
|
|
|
+ MinioUtil.rmR(minioClient, bucketName, projectResultPathOfMinio + projectId + "/");
|
|
|
+ // 删除算法key
|
|
|
+ // 删除yaml路径redis
|
|
|
+ // 删除记录podNamekey
|
|
|
+ RedisUtil.deleteByPrefix(stringRedisTemplate, "multi_project:" + projectId);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ public MultiProjectWaitQueueEntity createMultiTaskAndFixData(MultiSimulationProjectKafkaParam projectStartMessageEntity) {
|
|
|
+ //* -------------------------------- 0 读取消息,创建临时目录 --------------------------------
|
|
|
+ String projectId = projectStartMessageEntity.getProjectId(); // 手动执行项目 id 或 自动执行子项目 id
|
|
|
+ try {
|
|
|
+
|
|
|
+ List<MultiSimulationSceneKafkaParam> kafkaParamList = projectStartMessageEntity.getKafkaParamList();
|
|
|
+
|
|
|
+ List<MultiTaskMessageEntity> entityList = new ArrayList<>();
|
|
|
+ for (MultiSimulationSceneKafkaParam kafkaParam: kafkaParamList) {
|
|
|
+ String taskId = StringUtil.getRandomUUID();
|
|
|
+ String mapId = kafkaParam.getMapId();
|
|
|
+ String sceneId = kafkaParam.getId();
|
|
|
+ String minioUploadPath = projectId + "/" + taskId + "/";
|
|
|
+ SimulationMapVO simulationMapVO = mapMapper.selectMapByMapId(mapId);
|
|
|
+ if (Objects.isNull(simulationMapVO)){
|
|
|
+ throw new RuntimeException("地图" + mapId + "不存在");
|
|
|
+ }
|
|
|
+ String mapPath = simulationMapVO.getMapPath();
|
|
|
+ String mapOsgbPath = simulationMapVO.getMapOsgbPath();
|
|
|
+
|
|
|
+ String mapMinioPath = mapPath.substring(mapPath.indexOf("/mapFile"), mapPath.indexOf("?"));
|
|
|
+ String[] mapDriverSp = mapMinioPath.split("/");
|
|
|
+ String mapDriverSpName = mapDriverSp[mapDriverSp.length - 1];
|
|
|
+ String[] mapDriverNameSp = mapDriverSpName.split("\\.");
|
|
|
+ String mapDriverLast = mapDriverNameSp[mapDriverNameSp.length - 1];
|
|
|
+ String mapDriverLinuxPath = linuxTempPath + "multiProject/" + projectId + "/" + taskId + "/" + mapDriverSpName;
|
|
|
+ String mapDriverPathOfMinio = projectResultPathOfMinio + minioUploadPath + taskId + "." + mapDriverLast;
|
|
|
+ MinioUtil.downloadToFile(minioClient, bucketName, mapMinioPath, mapDriverLinuxPath);
|
|
|
+ MinioUtil.uploadFromFile(minioClient, mapDriverLinuxPath, bucketName, mapDriverPathOfMinio);
|
|
|
+ FileUtil.rm(mapDriverLinuxPath); // 删除临时文件
|
|
|
+
|
|
|
+ String mapOsgMinioPath = mapOsgbPath.substring(mapOsgbPath.indexOf("/mapFile"), mapOsgbPath.indexOf("?"));
|
|
|
+ String[] mapOsgSp = mapOsgMinioPath.split("/");
|
|
|
+ String mapOsgSpName = mapOsgSp[mapOsgSp.length - 1];
|
|
|
+ String[] mapOsgSpNameSp = mapOsgSpName.split("\\.");
|
|
|
+ String mapOsgSpNameSpLast = mapOsgSpNameSp[mapOsgSpNameSp.length - 1];
|
|
|
+ String mapOsgLinuxPath = linuxTempPath + "multiProject/" + projectId + "/" + taskId + "/" + mapOsgSpName;
|
|
|
+ String mapOsgPathOfMinio = projectResultPathOfMinio + minioUploadPath + taskId + "." + mapOsgSpNameSpLast;
|
|
|
+ MinioUtil.downloadToFile(minioClient, bucketName, mapOsgMinioPath, mapOsgLinuxPath);
|
|
|
+ MinioUtil.uploadFromFile(minioClient, mapOsgLinuxPath, bucketName, mapOsgPathOfMinio);
|
|
|
+ FileUtil.rm(mapOsgLinuxPath); // 删除临时文件
|
|
|
+
|
|
|
+ // 生成并上传xml
|
|
|
+ JSONObject carJson = new JSONObject();
|
|
|
+ carJson.put("numOfVehicle", kafkaParam.getSimulationSceneCarVOList().size());
|
|
|
+ JSONArray carArray = new JSONArray();
|
|
|
+
|
|
|
+ List<MultiSimulationSceneCarVO> simulationSceneCarVOList = kafkaParam.getSimulationSceneCarVOList();
|
|
|
+ if (CollectionUtils.isEmpty(simulationSceneCarVOList)){
|
|
|
+ throw new RuntimeException("未配置车辆");
|
|
|
+ }
|
|
|
+ VehicleEntity vehicle = null;
|
|
|
+ for (MultiSimulationSceneCarVO sceneCar: simulationSceneCarVOList) {
|
|
|
+ String sceneCarId = sceneCar.getId();
|
|
|
+ // 处理算法id
|
|
|
+ String algorithmId = sceneCar.getAlgorithmId();
|
|
|
+ log.info("项目:" + projectId + ",场景:" + sceneId + ",车辆id:" + sceneCarId + ",开始算法导入。");
|
|
|
+ String algorithmDockerImage = handleAlgorithm(sceneId, algorithmId);
|
|
|
+ log.info("项目:" + projectId + ",场景:" + sceneId + ",车辆id:" + sceneCarId + ",算法已导入" + algorithmDockerImage);
|
|
|
+// result.put("sceneCarId-" + sceneCarId + "-docker-image", algorithmDockerImage);
|
|
|
+ customRedisClient.set(projectDomainService.getMultiAlgorithmIdRedisKey(algorithmId, projectId), algorithmDockerImage);
|
|
|
+ // 处理车辆,一个场景的车辆是一样的,只需取第一个车辆即可
|
|
|
+ if (vehicle == null){
|
|
|
+ String carId = sceneCar.getCarId();
|
|
|
+ //1 根据车辆配置id vehicleConfigId, 获取 模型信息和传感器信息
|
|
|
+ com.css.simulation.resource.scheduler.infra.entity.VehicleEntity vehicleEntity = vehicleMapper.selectByVehicleConfigId(carId); // 车辆
|
|
|
+ List<CameraEntity> cameraEntityList = sensorCameraMapper.selectCameraByVehicleConfigId(carId); // 摄像头
|
|
|
+ List<OgtEntity> ogtEntityList = sensorOgtMapper.selectOgtByVehicleId(carId); // 完美传感器
|
|
|
+ vehicle = VehicleEntity.builder().model(ModelEntity.builder().model_label(vehicleEntity.getModelLabel()).build())
|
|
|
+ .dynamics(DynamicsEntity.builder().dynamics_maxspeed(vehicleEntity.getMaxSpeed()).dynamics_enginepower(vehicleEntity.getEnginePower()).dynamics_maxdecel(vehicleEntity.getMaxDeceleration()).dynamics_maxsteering(vehicleEntity.getMaxSteeringAngle()).dynamics_mass(vehicleEntity.getMass()).dynamics_frontsurfaceeffective(vehicleEntity.getFrontSurfaceEffective()).dynamics_airdragcoefficient(vehicleEntity.getAirDragCoefficient()).dynamics_rollingresistance(vehicleEntity.getRollingResistanceCoefficient()).dynamics_wheeldiameter(vehicleEntity.getWheelDiameter()).dynamics_wheeldrive(vehicleEntity.getWheelDrive()).dynamics_overallefficiency(vehicleEntity.getOverallEfficiency()).dynamics_distfront(vehicleEntity.getFrontDistance()).dynamics_distrear(vehicleEntity.getRearDistance()).dynamics_distleft(vehicleEntity.getLeftDistance()).dynamics_distright(vehicleEntity.getRightDistance()).dynamics_distheight(vehicleEntity.getHeightDistance()).dynamics_wheelbase(vehicleEntity.getWheelbase()).build())
|
|
|
+ .sensors(SensorsEntity.builder() // 根据 vehicleId 查询绑定的传感器列表
|
|
|
+ .camera(cameraEntityList).OGT(ogtEntityList).build()).build();
|
|
|
+ }
|
|
|
+ String pathStart = sceneCar.getPathStart();
|
|
|
+ JSONObject jsonObject = JSONObject.parseObject(pathStart);
|
|
|
+ jsonObject.remove("name");
|
|
|
+ carArray.add(jsonObject);
|
|
|
+ }
|
|
|
+ carJson.put("position", carArray);
|
|
|
+ // 生成xml文件
|
|
|
+ String mapXmlLinuxPath = linuxTempPath + "multiProject/" + projectId + "/" + taskId + "/" + taskId + ".xml";
|
|
|
+ String mapJsonLinuxPath = linuxTempPath + "multiProject/" + projectId + "/" + taskId + "/" + taskId + ".json";
|
|
|
+ FileUtil.writeStringToLocalFile(carJson.toJSONString(), mapJsonLinuxPath);
|
|
|
+ String linuxComm = multiVtdXmlGenerator + " " + mapXmlLinuxPath + " " + mapXmlLinuxPath;
|
|
|
+ LinuxUtil.execute(linuxComm);
|
|
|
+ String mapXmlPathOfMinio = projectResultPathOfMinio + minioUploadPath + taskId + ".xml";
|
|
|
+ MinioUtil.uploadFromFile(minioClient, mapXmlLinuxPath, bucketName, mapXmlPathOfMinio);
|
|
|
+ FileUtil.rm(mapXmlLinuxPath);
|
|
|
+ FileUtil.rm(mapJsonLinuxPath);
|
|
|
+
|
|
|
+ MultiTaskMessageEntity build = MultiTaskMessageEntity.builder().info(MultiInfoEntity.builder().project_id(projectId).task_id(taskId).scene_id(sceneId)
|
|
|
+ .default_time(Long.valueOf(projectStartMessageEntity.getDefaultTime()))
|
|
|
+ .task_path(projectResultPathOfMinio + minioUploadPath).build())
|
|
|
+ .scenario(ScenarioEntity.builder().scenario_osc(mapXmlPathOfMinio).scenario_odr(mapDriverPathOfMinio).scenario_osgb(mapOsgPathOfMinio).build())
|
|
|
+ .vehicleEntity(vehicle)
|
|
|
+ .build();
|
|
|
+ entityList.add(build);
|
|
|
+ }
|
|
|
+ int sort = 0;
|
|
|
+ for (MultiTaskMessageEntity entity: entityList) {
|
|
|
+ taskRecordMapper.addMultiSimulationProjectTaskRecord(entity.getInfo().getTask_id(), entity.getInfo().getScene_id(), entity.getInfo().getProject_id(),
|
|
|
+ JSONObject.toJSONString(entity), sort);
|
|
|
+ sort ++;
|
|
|
+ }
|
|
|
+ log.info("project:{},共插入{}条数据", projectId, entityList.size());
|
|
|
+ MultiProjectWaitQueueEntity build = MultiProjectWaitQueueEntity.builder()
|
|
|
+ .multiTaskMessageEntityList(entityList)
|
|
|
+ .projectId(projectId)
|
|
|
+ .waitingParallelism(entityList.size())
|
|
|
+ .kafkaParamList(kafkaParamList)
|
|
|
+ .build();
|
|
|
+ return build;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("项目报错。", e);
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ @SneakyThrows
|
|
|
+ // TODO 此处加锁
|
|
|
+ public void checkIfCanRunMulti(MultiProjectWaitQueueEntity projectWaitQueueEntity) {
|
|
|
+// List<MultiTaskMessageEntity> multiTaskMessageEntityList = projectWaitQueueEntity.getMultiTaskMessageEntityList();
|
|
|
+ //1 项目信息
|
|
|
+ int parallelism = projectWaitQueueEntity.getWaitingParallelism();
|
|
|
+ if (parallelism <=0){
|
|
|
+ log.info("需要只需的项目并行度为0");
|
|
|
+ }
|
|
|
+ String isChoiceGpu = DictConstants.USE_GPU;
|
|
|
+ final UserEntity userEntity = projectDomainService.getUserEntityByMultiProjectId(projectWaitQueueEntity.getProjectId());
|
|
|
+ String projectUserId = userEntity.getId();
|
|
|
+ String roleCode = userEntity.getRoleCode();
|
|
|
+ String useType = userEntity.getUseType();
|
|
|
+
|
|
|
+ ClusterEntity clusterEntity = null;
|
|
|
+ String clusterUserId; // 项目实际运行使用的用户集群
|
|
|
+
|
|
|
+ if (DictConstants.ROLE_CODE_SYSADMIN.equals(roleCode) || DictConstants.ROLE_CODE_ADMIN.equals(roleCode)) { //3-1 管理员账户和管理员子账户直接执行
|
|
|
+ clusterUserId = DictConstants.SYSTEM_USER_ID;
|
|
|
+ } else if (DictConstants.ROLE_CODE_UESR.equals(roleCode)) { //3-2 普通账户,不管是独占还是共享,都在自己的集群里排队,根据自己的独占节点排队
|
|
|
+ clusterUserId = projectUserId;
|
|
|
+ clusterEntity = clusterMapper.selectByUserId(clusterUserId);
|
|
|
+
|
|
|
+ } else if (DictConstants.ROLE_CODE_SUBUESR.equals(roleCode)) {
|
|
|
+ if (DictConstants.USER_TYPE_EXCLUSIVE.equals(useType)) { //3-3 普通子账户,根据自己的独占节点排队
|
|
|
+ clusterUserId = projectUserId;
|
|
|
+ clusterEntity = clusterMapper.selectByUserId(clusterUserId);
|
|
|
+ } else if (DictConstants.USER_TYPE_PUBLIC.equals(useType)) { //3-4 共享子账户,根据父账户的共享节点排队
|
|
|
+ clusterUserId = userEntity.getCreateUserId();
|
|
|
+ clusterEntity = clusterMapper.selectByUserId(clusterUserId);
|
|
|
+ } else {
|
|
|
+ throw new RuntimeException("用户" + projectUserId + "未知占用类型:" + useType);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ throw new RuntimeException("未知角色类型:" + roleCode);
|
|
|
+ }
|
|
|
+ int remainderSimulationLicense = Integer.MAX_VALUE;
|
|
|
+ if (!clusterUserId.equals(DictConstants.SYSTEM_USER_ID)){
|
|
|
+ // 获取仿真软件证书数量和动力学软件证书数量(vtd占一个仿真证书,carsim各占一个)
|
|
|
+ Integer usingSimulationLicenseNumber = projectDomainService.getUsingLicenseNumber(clusterUserId, DictConstants.LICENSE_TYPE_SIMULATION);
|
|
|
+ Integer numSimulationLicense = clusterEntity.getNumSimulationLicense();
|
|
|
+ // 判断仿真证书是否够用,如果证书为0则将项目加入等待队列;如果证书小于并行度则加入扩充队列,并用现有证书执行;如果证书够用,直接执行。
|
|
|
+ remainderSimulationLicense = numSimulationLicense - usingSimulationLicenseNumber;
|
|
|
+ }
|
|
|
+
|
|
|
+ //2 剩余并行度
|
|
|
+ // 考虑仿真证书数量
|
|
|
+ // 剩余并行度
|
|
|
+ int remainderParallelism = projectDomainService.getRemainderMultiParallelism(isChoiceGpu);
|
|
|
+ log.info("计算出剩余可执行的并行度:{}", remainderParallelism);
|
|
|
+ boolean needWait = false;
|
|
|
+ if (DictConstants.SYSTEM_USER_ID.equals(clusterUserId)){
|
|
|
+ // 不需要判断证书
|
|
|
+ } else{
|
|
|
+ if (remainderSimulationLicense <= 0){
|
|
|
+ log.info("multiProjectId:{},仿真数量不够用clusterUserId:{}", projectWaitQueueEntity.getProjectId(), clusterUserId);
|
|
|
+ needWait = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+// else if (projectWaitQueueEntity.getRunState() <0 && remainderParallelism >0){
|
|
|
+// // 首次执行,且可以执行,不进入等待队列
|
|
|
+// if (remainderSimulationLicense <= 0){
|
|
|
+// needWait = true;
|
|
|
+// } else {
|
|
|
+// // 消耗一个证书
|
|
|
+// if (!DictConstants.SYSTEM_USER_ID.equals(clusterUserId)){
|
|
|
+// projectDomainService.useLicense(clusterUserId, 1);
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+ if (remainderParallelism <= 0 || needWait) {
|
|
|
+ waitMulti(projectWaitQueueEntity);
|
|
|
+ } else if (remainderParallelism < parallelism) {
|
|
|
+ // 初始执行
|
|
|
+ if (projectWaitQueueEntity.getRunState() <0){
|
|
|
+ log.info("多模式仿真初始执行,创建kafka topic:{}", projectWaitQueueEntity.getProjectId());
|
|
|
+ KafkaUtil.createTopic(kafkaAdminClient, projectWaitQueueEntity.getProjectId(), projectWaitQueueEntity.getMultiTaskMessageEntityList().size(), (short) 1); // 创建主题
|
|
|
+ TimeUnit.SECONDS.sleep(5);
|
|
|
+ if (!DictConstants.SYSTEM_USER_ID.equals(clusterUserId)){
|
|
|
+ projectDomainService.useLicense(clusterUserId, 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 执行完之后删除之前的list.
|
|
|
+ // 现有逻辑不需要不需要再删除list了
|
|
|
+ runMulti(remainderParallelism, projectWaitQueueEntity, isChoiceGpu);
|
|
|
+ Integer runState = projectWaitQueueEntity.getRunState();
|
|
|
+ int runSt = remainderParallelism + runState;
|
|
|
+ waitMulti(MultiProjectWaitQueueEntity.builder().waitingParallelism(parallelism - remainderParallelism)
|
|
|
+ .runState(runSt)
|
|
|
+ .multiTaskMessageEntityList(projectWaitQueueEntity.getMultiTaskMessageEntityList())
|
|
|
+ .kafkaParamList(projectWaitQueueEntity.getKafkaParamList())
|
|
|
+ .build());
|
|
|
+ } else {
|
|
|
+ if (projectWaitQueueEntity.getRunState() <0){
|
|
|
+ log.info("多模式仿真初始执行,剩余并行度够用,创建kafka topic:{}", projectWaitQueueEntity.getProjectId());
|
|
|
+ KafkaUtil.createTopic(kafkaAdminClient, projectWaitQueueEntity.getProjectId(), projectWaitQueueEntity.getMultiTaskMessageEntityList().size(), (short) 1); // 创建主题
|
|
|
+ TimeUnit.SECONDS.sleep(5);
|
|
|
+ if (!DictConstants.SYSTEM_USER_ID.equals(clusterUserId)){
|
|
|
+ projectDomainService.useLicense(clusterUserId, 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ runMulti(parallelism, projectWaitQueueEntity, isChoiceGpu);
|
|
|
+ // 能执行完也需要删除之前redis key
|
|
|
+ waitMulti(MultiProjectWaitQueueEntity.builder().waitingParallelism(0)
|
|
|
+ .runState(projectWaitQueueEntity.getMultiTaskMessageEntityList().size() -1)
|
|
|
+ .kafkaParamList(projectWaitQueueEntity.getKafkaParamList())
|
|
|
+ .multiTaskMessageEntityList(projectWaitQueueEntity.getMultiTaskMessageEntityList()).build()
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
}
|