v2
This commit is contained in:
		| @@ -0,0 +1,27 @@ | |||||||
|  | package com.weilab.biology.config; | ||||||
|  |  | ||||||
|  | import com.weilab.biology.service.JobService; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | import org.springframework.beans.factory.annotation.Autowired; | ||||||
|  | import org.springframework.context.annotation.Configuration; | ||||||
|  | import org.springframework.scheduling.annotation.EnableScheduling; | ||||||
|  | import org.springframework.scheduling.annotation.Scheduled; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @Configuration | ||||||
|  | @EnableScheduling | ||||||
|  | @Slf4j | ||||||
|  | public class StaticScheduleTask { | ||||||
|  |  | ||||||
|  |     @Autowired | ||||||
|  |     private JobService jobService; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 一分钟执行一次 | ||||||
|  |      */ | ||||||
|  |     @Scheduled(fixedRate = 60 * 1000L) | ||||||
|  |     public void crawlStudyRoomFrequently() { | ||||||
|  |         jobService.runJob(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -3,9 +3,10 @@ package com.weilab.biology.controller; | |||||||
| import cn.hutool.core.io.FileUtil; | import cn.hutool.core.io.FileUtil; | ||||||
| import cn.hutool.core.util.IdUtil; | import cn.hutool.core.util.IdUtil; | ||||||
| import cn.hutool.core.util.StrUtil; | import cn.hutool.core.util.StrUtil; | ||||||
|  | import cn.hutool.json.JSONUtil; | ||||||
| import com.alibaba.fastjson.JSON; | import com.alibaba.fastjson.JSON; | ||||||
| import com.alibaba.fastjson.JSONObject; | import com.alibaba.fastjson.JSONObject; | ||||||
| import com.baomidou.mybatisplus.core.toolkit.StringUtils; | import com.weilab.biology.core.data.dto.AppConfigDto; | ||||||
| import com.weilab.biology.core.data.dto.JobDto; | import com.weilab.biology.core.data.dto.JobDto; | ||||||
| import com.weilab.biology.core.data.enums.JobStatusEnum; | import com.weilab.biology.core.data.enums.JobStatusEnum; | ||||||
| import com.weilab.biology.core.data.po.Job; | import com.weilab.biology.core.data.po.Job; | ||||||
| @@ -14,18 +15,19 @@ import com.weilab.biology.core.data.vo.result.Result; | |||||||
| import com.weilab.biology.core.data.vo.result.error.JobError; | import com.weilab.biology.core.data.vo.result.error.JobError; | ||||||
| import com.weilab.biology.core.validation.EnumValidation; | import com.weilab.biology.core.validation.EnumValidation; | ||||||
| import com.weilab.biology.mapper.JobMapper; | import com.weilab.biology.mapper.JobMapper; | ||||||
|  | import com.weilab.biology.service.AppConfigService; | ||||||
| import com.weilab.biology.service.JobService; | import com.weilab.biology.service.JobService; | ||||||
| import com.weilab.biology.util.FileUtils; |  | ||||||
| import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||||
| import org.springframework.beans.factory.annotation.Value; | import org.springframework.beans.factory.annotation.Value; | ||||||
| import org.springframework.web.bind.annotation.*; | import org.springframework.web.bind.annotation.GetMapping; | ||||||
|  | import org.springframework.web.bind.annotation.PathVariable; | ||||||
|  | import org.springframework.web.bind.annotation.PostMapping; | ||||||
|  | import org.springframework.web.bind.annotation.RequestMapping; | ||||||
|  | import org.springframework.web.bind.annotation.RequestParam; | ||||||
|  | import org.springframework.web.bind.annotation.RestController; | ||||||
| import org.springframework.web.multipart.MultipartFile; | import org.springframework.web.multipart.MultipartFile; | ||||||
|  |  | ||||||
| import java.io.BufferedInputStream; |  | ||||||
| import java.io.IOException; |  | ||||||
| import java.time.LocalDateTime; | import java.time.LocalDateTime; | ||||||
| import java.util.Arrays; |  | ||||||
| import java.util.List; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @RestController | @RestController | ||||||
| @@ -35,6 +37,9 @@ public class JobController { | |||||||
|     @Autowired |     @Autowired | ||||||
|     private JobService jobService; |     private JobService jobService; | ||||||
|  |  | ||||||
|  |     @Autowired | ||||||
|  |     private AppConfigService appConfigService; | ||||||
|  |  | ||||||
|     @Autowired |     @Autowired | ||||||
|     private JobMapper jobMapper; |     private JobMapper jobMapper; | ||||||
|  |  | ||||||
| @@ -42,66 +47,20 @@ public class JobController { | |||||||
|     private String requestPath; |     private String requestPath; | ||||||
|  |  | ||||||
|     @PostMapping("/submit") |     @PostMapping("/submit") | ||||||
|     public Result submit(@RequestParam(required = false) Long jobId, |     public Result submit(@RequestParam String appName, | ||||||
|  |                          @RequestParam(required = false) Long jobId, | ||||||
|                          @RequestParam(required = false) String dataStr, |                          @RequestParam(required = false) String dataStr, | ||||||
|                          @RequestParam(required = false) MultipartFile dataFile, |                          @RequestParam(required = false) MultipartFile dataFile, | ||||||
|                          @RequestParam String param, |                          @RequestParam String param, | ||||||
|                          @RequestParam String mail, |                          @RequestParam String mail, | ||||||
|                          @RequestParam(defaultValue = "0") Integer type, |                          @RequestParam(defaultValue = "0") Integer type) { | ||||||
|                          @RequestParam(required = false) MultipartFile file1, |         if (dataFile == null && StrUtil.isBlank(dataStr)) { | ||||||
|                          @RequestParam(required = false) MultipartFile file2, |  | ||||||
|                          @RequestParam(required = false) MultipartFile file3, |  | ||||||
|                          @RequestParam(required = false) MultipartFile file4, |  | ||||||
|                          @RequestParam(required = false) MultipartFile file5, |  | ||||||
|                          @RequestParam(required = false) MultipartFile file6, |  | ||||||
|                          @RequestParam(required = false) MultipartFile file7, |  | ||||||
|                          @RequestParam(required = false) MultipartFile file8, |  | ||||||
|                          @RequestParam(required = false) MultipartFile file9, |  | ||||||
|                          @RequestParam(required = false) MultipartFile file10, |  | ||||||
|                          @RequestParam(required = false) MultipartFile file11, |  | ||||||
|                          @RequestParam(required = false) MultipartFile file12, |  | ||||||
|                          @RequestParam(required = false) MultipartFile file13, |  | ||||||
|                          @RequestParam(required = false) MultipartFile file14, |  | ||||||
|                          @RequestParam(required = false) MultipartFile file15, |  | ||||||
|                          @RequestParam(required = false) MultipartFile file16, |  | ||||||
|                          @RequestParam(required = false) MultipartFile file17, |  | ||||||
|                          @RequestParam(required = false) MultipartFile file18, |  | ||||||
|                          @RequestParam(required = false) MultipartFile file19, |  | ||||||
|                          @RequestParam(required = false) MultipartFile file20) { |  | ||||||
|         if (dataFile == null && StringUtils.isBlank(dataStr)) { |  | ||||||
|             return Result.getResult(JobError.PARAM_CAN_NOT_BE_EMPTY); |             return Result.getResult(JobError.PARAM_CAN_NOT_BE_EMPTY); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // 解析param字符串为map对象 |         AppConfigDto appConfig = appConfigService.getAppConfig(appName); | ||||||
|         JSONObject reqParamMap = null; |         if (appConfig == null) { | ||||||
|         try { |             return Result.getResult(JobError.APP_NOT_FOUND); | ||||||
|             reqParamMap = JSON.parseObject(param); |  | ||||||
|         } catch (Exception e) { |  | ||||||
|             return Result.getResult(CommonError.PARAM_WRONG); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // 写入file文件,并将文件路径放入paramMap |  | ||||||
|         try { |  | ||||||
|             List<MultipartFile> files = Arrays.asList(file1, file2, file3, file4, file5, |  | ||||||
|                     file6, file7, file8, file9, file10, file11, file12, file13, file14, file15, |  | ||||||
|                     file16, file17, file18, file19, file20); |  | ||||||
|             for (MultipartFile file : files) { |  | ||||||
|                 if (file != null) { |  | ||||||
|                     String filePath = requestPath + FileUtil.FILE_SEPARATOR + "file" + FileUtil.FILE_SEPARATOR |  | ||||||
|                             + IdUtil.fastUUID() + "." + FileUtil.extName(file.getOriginalFilename()); |  | ||||||
|                     FileUtil.writeFromStream(file.getInputStream(), filePath); |  | ||||||
|                     reqParamMap.put(file.getName(), filePath); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } catch (IOException e) { |  | ||||||
|             e.printStackTrace(); |  | ||||||
|             return Result.getResult(JobError.FILE_READ_FAIL); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // 将请求数据file转为InputStream |  | ||||||
|         BufferedInputStream dataStream = null; |  | ||||||
|         if (dataFile != null) { |  | ||||||
|             dataStream = FileUtil.getInputStream(FileUtils.multipartToFile(dataFile)); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         Job job = null; |         Job job = null; | ||||||
| @@ -115,32 +74,46 @@ public class JobController { | |||||||
|             job = new Job(); |             job = new Job(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (!StrUtil.isEmpty(job.getParam())) { |         // 解析param字符串为map对象 | ||||||
|             JSONObject params = JSON.parseObject(job.getParam()); |         JSONObject reqParamMap = null; | ||||||
|             params.putAll(reqParamMap); |         try { | ||||||
|             reqParamMap = params; |             reqParamMap = JSON.parseObject(param); | ||||||
|             job.setParam(JSON.toJSONString(reqParamMap)); |         } catch (Exception e) { | ||||||
|  |             return Result.getResult(CommonError.PARAM_WRONG); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         job.setData(""); |         // 将reqParam覆盖添加到原有job的param中 | ||||||
|  |         JSONObject params = JSON.parseObject(job.getParam()); | ||||||
|  |         params.putAll(reqParamMap); | ||||||
|  |         job.setParam(JSON.toJSONString(params)); | ||||||
|  |         job.setAppId(appConfig.getAppId()); | ||||||
|         job.setMail(mail); |         job.setMail(mail); | ||||||
|         job.setStatus(JobStatusEnum.WAIT.getKey()); |         job.setStatus(JobStatusEnum.WAITING.getKey()); | ||||||
|         job.setRequestTime(LocalDateTime.now()); |         job.setCreateTime(LocalDateTime.now()); | ||||||
|         job.setType(type); |         job.setType(type); | ||||||
|  |  | ||||||
|         return jobService.submit(dataStr, dataStream, reqParamMap, job); |         return jobService.submit(appConfig, dataStr, dataFile, reqParamMap, job); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @PostMapping("/create") |     @PostMapping("/create") | ||||||
|     public Result createJob() { |     public Result createJob(@RequestParam String appName) { | ||||||
|  |         AppConfigDto appConfig = appConfigService.getAppConfig(appName); | ||||||
|  |         if (appConfig == null) { | ||||||
|  |             return Result.getResult(JobError.APP_NOT_FOUND); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         Job job = new Job(); |         Job job = new Job(); | ||||||
|  |         job.setAppId(appConfig.getAppId()); | ||||||
|         job.setParam("{}"); |         job.setParam("{}"); | ||||||
|         job.setStatus(JobStatusEnum.CREATING.getKey()); |         job.setStatus(JobStatusEnum.CREATING.getKey()); | ||||||
|         job.setRequestTime(LocalDateTime.now()); |         job.setCreateTime(LocalDateTime.now()); | ||||||
|         jobMapper.insert(job); |         jobMapper.insert(job); | ||||||
|         return Result.success(JobDto.parseJob(job)); |         return Result.success(JobDto.parseJob(job)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 上传文件接口,将文件地址保存至本地,并将路径放入参数中 | ||||||
|  |      */ | ||||||
|     @PostMapping("/file/upload") |     @PostMapping("/file/upload") | ||||||
|     public Result uploadFile(@RequestParam Long jobId, |     public Result uploadFile(@RequestParam Long jobId, | ||||||
|                              @RequestParam String fileKey, |                              @RequestParam String fileKey, | ||||||
| @@ -152,7 +125,6 @@ public class JobController { | |||||||
|  |  | ||||||
|         JSONObject params = JSON.parseObject(job.getParam()); |         JSONObject params = JSON.parseObject(job.getParam()); | ||||||
|         try { |         try { | ||||||
|             if (file != null) { |  | ||||||
|             String extName = FileUtil.extName(file.getOriginalFilename()); |             String extName = FileUtil.extName(file.getOriginalFilename()); | ||||||
|             if (!StrUtil.isEmpty(extName)) { |             if (!StrUtil.isEmpty(extName)) { | ||||||
|                 extName = StrUtil.DOT + extName; |                 extName = StrUtil.DOT + extName; | ||||||
| @@ -165,30 +137,32 @@ public class JobController { | |||||||
|             job.setParam(JSON.toJSONString(params)); |             job.setParam(JSON.toJSONString(params)); | ||||||
|             jobMapper.updateById(job); |             jobMapper.updateById(job); | ||||||
|             return Result.success(JobDto.parseJob(job)); |             return Result.success(JobDto.parseJob(job)); | ||||||
|             } |  | ||||||
|         } catch (Exception e) { |         } catch (Exception e) { | ||||||
|             e.printStackTrace(); |             e.printStackTrace(); | ||||||
|         } |  | ||||||
|             return Result.fail(); |             return Result.fail(); | ||||||
|         } |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @PostMapping("/status/update") |     @PostMapping("/status/update") | ||||||
|     public Result updateJobStatus(@RequestParam Integer jobId, |     public Result updateJobStatus(@RequestParam Integer jobId, | ||||||
|                                   @EnumValidation(clazz = JobStatusEnum.class, message = "没有此状态") |                                   @EnumValidation(clazz = JobStatusEnum.class, message = "没有此状态") @RequestParam Integer status, | ||||||
|                                   @RequestParam Integer status, |  | ||||||
|                                   @RequestParam(required = false) String result) { |                                   @RequestParam(required = false) String result) { | ||||||
|         if (status.equals(JobStatusEnum.WAIT.getKey())) |         if (status.equals(JobStatusEnum.WAITING.getKey())) { | ||||||
|             return Result.getResult(CommonError.PARAM_WRONG); |             return Result.getResult(CommonError.PARAM_WRONG); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         if (status.equals(JobStatusEnum.SUCCESS.getKey())) { |         if (status.equals(JobStatusEnum.SUCCESS.getKey())) { | ||||||
|             if (StringUtils.isBlank(result)) |             if (!JSONUtil.isJson(result)) { | ||||||
|                 return Result.getResult(CommonError.PARAM_WRONG); |  | ||||||
|             try { |  | ||||||
|                 JSON.parseObject(result); |  | ||||||
|             } catch (Exception e) { |  | ||||||
|                 return Result.getResult(CommonError.PARAM_WRONG); |                 return Result.getResult(CommonError.PARAM_WRONG); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         return jobService.updateJobStatus(jobId, JobStatusEnum.getEnumByKey(status), result); |  | ||||||
|  |         Job job = jobMapper.selectById(jobId); | ||||||
|  |         if (job == null) { | ||||||
|  |             return Result.getResult(CommonError.CONTENT_NOT_FOUND); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return jobService.updateJobStatus(job, JobStatusEnum.getEnumByKey(status), result); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @GetMapping("/info/{jobId}") |     @GetMapping("/info/{jobId}") | ||||||
| @@ -196,16 +170,17 @@ public class JobController { | |||||||
|         return jobService.getJobInfo(jobId); |         return jobService.getJobInfo(jobId); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @GetMapping("/list") |  | ||||||
|     public Result getJobList(@RequestParam(required = false) Integer type) { |  | ||||||
|         return jobService.getJobList(type); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @GetMapping("/list/v2") |     @GetMapping("/list/v2") | ||||||
|     public Result getJobList(@RequestParam(required = false) Integer type, |     public Result getJobList(@RequestParam String appName, | ||||||
|  |                              @RequestParam(required = false) Integer type, | ||||||
|                              @RequestParam(defaultValue = "true") Boolean filterCreating, |                              @RequestParam(defaultValue = "true") Boolean filterCreating, | ||||||
|                              @RequestParam(defaultValue = "1") Integer page, |                              @RequestParam(defaultValue = "1") Integer page, | ||||||
|                              @RequestParam(defaultValue = "100") Integer size) { |                              @RequestParam(defaultValue = "100") Integer size) { | ||||||
|         return jobService.getJobList(type, filterCreating, page, size); |         AppConfigDto appConfig = appConfigService.getAppConfig(appName); | ||||||
|  |         if (appConfig == null) { | ||||||
|  |             return Result.getResult(JobError.APP_NOT_FOUND); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return jobService.getJobList(appConfig.getAppId(), type, filterCreating, page, size); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,94 @@ | |||||||
|  | package com.weilab.biology.core.data.dto; | ||||||
|  |  | ||||||
|  | import com.alibaba.fastjson.JSON; | ||||||
|  | import com.alibaba.fastjson.JSONObject; | ||||||
|  | import com.weilab.biology.core.data.po.AppConfig; | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.EqualsAndHashCode; | ||||||
|  | import lombok.experimental.Accessors; | ||||||
|  |  | ||||||
|  | import java.io.File; | ||||||
|  | import java.io.Serializable; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 应用配置信息Dto | ||||||
|  |  * | ||||||
|  |  * @author yurui | ||||||
|  |  * @date 2023/5/5 | ||||||
|  |  */ | ||||||
|  | @Data | ||||||
|  | @EqualsAndHashCode(callSuper = false) | ||||||
|  | @Accessors(chain = true) | ||||||
|  | public class AppConfigDto implements Serializable { | ||||||
|  |  | ||||||
|  |     private static final long serialVersionUID = 1L; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 应用ID | ||||||
|  |      */ | ||||||
|  |     private Integer appId; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 应用名 | ||||||
|  |      */ | ||||||
|  |     private String appName; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 并发数 | ||||||
|  |      */ | ||||||
|  |     private Integer concurrentNum; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 命令行 | ||||||
|  |      */ | ||||||
|  |     private String cmd; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 任务超时时间(单位:分钟) | ||||||
|  |      */ | ||||||
|  |     private Long timeout; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 放置文件的路径 | ||||||
|  |      */ | ||||||
|  |     private String localPath; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 放置请求参数文件的路径 | ||||||
|  |      */ | ||||||
|  |     private String requestPath; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 放置结果文件的路径 | ||||||
|  |      */ | ||||||
|  |     private String resultPath; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 放置日志文件的路径 | ||||||
|  |      */ | ||||||
|  |     private String logPath; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 邮件格式(json格式:{"subject":"**","success":"**"}) | ||||||
|  |      */ | ||||||
|  |     private JSONObject emailTemplate; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     public static AppConfigDto parse(AppConfig o) { | ||||||
|  |         if (o == null) { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |         return new AppConfigDto() | ||||||
|  |                 .setAppId(o.getAppId()) | ||||||
|  |                 .setAppName(o.getAppName()) | ||||||
|  |                 .setConcurrentNum(o.getConcurrentNum()) | ||||||
|  |                 .setCmd(o.getCmd()) | ||||||
|  |                 .setTimeout(o.getTimeout()) | ||||||
|  |                 .setLocalPath(o.getLocalPath()) | ||||||
|  |                 .setRequestPath(o.getLocalPath() + File.separator + "request" + File.separator) | ||||||
|  |                 .setResultPath(o.getLocalPath() + File.separator + "result" + File.separator) | ||||||
|  |                 .setLogPath(o.getLocalPath() + File.separator + "log" + File.separator) | ||||||
|  |                 .setEmailTemplate(JSON.parseObject(o.getEmailTemplate())); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -2,9 +2,6 @@ package com.weilab.biology.core.data.dto; | |||||||
|  |  | ||||||
| import com.alibaba.fastjson.JSON; | import com.alibaba.fastjson.JSON; | ||||||
| import com.alibaba.fastjson.JSONObject; | import com.alibaba.fastjson.JSONObject; | ||||||
| import com.baomidou.mybatisplus.annotation.IdType; |  | ||||||
| import com.baomidou.mybatisplus.annotation.TableField; |  | ||||||
| import com.baomidou.mybatisplus.annotation.TableId; |  | ||||||
| import com.fasterxml.jackson.annotation.JsonFormat; | import com.fasterxml.jackson.annotation.JsonFormat; | ||||||
| import com.weilab.biology.core.data.enums.JobStatusEnum; | import com.weilab.biology.core.data.enums.JobStatusEnum; | ||||||
| import com.weilab.biology.core.data.po.Job; | import com.weilab.biology.core.data.po.Job; | ||||||
| @@ -12,12 +9,15 @@ import lombok.AllArgsConstructor; | |||||||
| import lombok.Data; | import lombok.Data; | ||||||
| import lombok.NoArgsConstructor; | import lombok.NoArgsConstructor; | ||||||
|  |  | ||||||
|  | import java.io.Serializable; | ||||||
| import java.time.LocalDateTime; | import java.time.LocalDateTime; | ||||||
|  |  | ||||||
| @Data | @Data | ||||||
| @AllArgsConstructor | @AllArgsConstructor | ||||||
| @NoArgsConstructor | @NoArgsConstructor | ||||||
| public class JobDto { | public class JobDto implements Serializable { | ||||||
|  |  | ||||||
|  |     private static final long serialVersionUID = 1L; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * jobId |      * jobId | ||||||
|   | |||||||
| @@ -6,16 +6,37 @@ import java.util.HashMap; | |||||||
| import java.util.Map; | import java.util.Map; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * 校区的枚举类 |  * 任务状态的枚举类 | ||||||
|  */ |  */ | ||||||
| @Getter | @Getter | ||||||
| public enum JobStatusEnum { | public enum JobStatusEnum { | ||||||
|     WAIT(0, "waiting"), |     /** | ||||||
|  |      * 等待运行 | ||||||
|  |      */ | ||||||
|  |     WAITING(0, "waiting"), | ||||||
|  |     /** | ||||||
|  |      * 正在运行 | ||||||
|  |      */ | ||||||
|     RUNNING(1, "running"), |     RUNNING(1, "running"), | ||||||
|  |     /** | ||||||
|  |      * 任务执行成功 | ||||||
|  |      */ | ||||||
|     SUCCESS(2, "success"), |     SUCCESS(2, "success"), | ||||||
|  |     /** | ||||||
|  |      * 已发送请求 | ||||||
|  |      */ | ||||||
|     REQED(3, "requested"), |     REQED(3, "requested"), | ||||||
|  |     /** | ||||||
|  |      * 任务执行失败 | ||||||
|  |      */ | ||||||
|     FAIL(-1, "failed"), |     FAIL(-1, "failed"), | ||||||
|  |     /** | ||||||
|  |      * 运行超时 | ||||||
|  |      */ | ||||||
|     TIMEOUT(-2, "timeout"), |     TIMEOUT(-2, "timeout"), | ||||||
|  |     /** | ||||||
|  |      * 正在创建 | ||||||
|  |      */ | ||||||
|     CREATING(-3, "creating"), |     CREATING(-3, "creating"), | ||||||
|     ; |     ; | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										70
									
								
								src/main/java/com/weilab/biology/core/data/po/AppConfig.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/main/java/com/weilab/biology/core/data/po/AppConfig.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | |||||||
|  | package com.weilab.biology.core.data.po; | ||||||
|  |  | ||||||
|  | import com.baomidou.mybatisplus.annotation.TableField; | ||||||
|  | import com.baomidou.mybatisplus.annotation.TableName; | ||||||
|  | import com.baomidou.mybatisplus.annotation.IdType; | ||||||
|  | import com.baomidou.mybatisplus.annotation.TableId; | ||||||
|  | import java.io.Serializable; | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.EqualsAndHashCode; | ||||||
|  | import lombok.experimental.Accessors; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * <p> | ||||||
|  |  * 应用配置信息 | ||||||
|  |  * </p> | ||||||
|  |  * | ||||||
|  |  * @author skyyemperor | ||||||
|  |  */ | ||||||
|  | @Data | ||||||
|  | @EqualsAndHashCode(callSuper = false) | ||||||
|  | @Accessors(chain = true) | ||||||
|  | @TableName("app_config") | ||||||
|  | public class AppConfig implements Serializable { | ||||||
|  |  | ||||||
|  |     private static final long serialVersionUID = 1L; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 应用ID | ||||||
|  |      */ | ||||||
|  |     @TableId(value = "app_id", type = IdType.AUTO) | ||||||
|  |     private Integer appId; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 应用名 | ||||||
|  |      */ | ||||||
|  |     @TableField("app_name") | ||||||
|  |     private String appName; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 并发数 | ||||||
|  |      */ | ||||||
|  |     @TableField("concurrent_num") | ||||||
|  |     private Integer concurrentNum; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 命令行 | ||||||
|  |      */ | ||||||
|  |     @TableField("cmd") | ||||||
|  |     private String cmd; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 任务超时时间(单位:分钟) | ||||||
|  |      */ | ||||||
|  |     @TableField("timeout") | ||||||
|  |     private Long timeout; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 放置文件的路径 | ||||||
|  |      */ | ||||||
|  |     @TableField("local_path") | ||||||
|  |     private String localPath; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 邮件格式(json格式:{"subject":"**","success":"**"}) | ||||||
|  |      */ | ||||||
|  |     @TableField("email_template") | ||||||
|  |     private String emailTemplate; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -4,17 +4,13 @@ import com.baomidou.mybatisplus.annotation.IdType; | |||||||
| import com.baomidou.mybatisplus.annotation.TableField; | import com.baomidou.mybatisplus.annotation.TableField; | ||||||
| import com.baomidou.mybatisplus.annotation.TableId; | import com.baomidou.mybatisplus.annotation.TableId; | ||||||
| import com.baomidou.mybatisplus.annotation.TableName; | import com.baomidou.mybatisplus.annotation.TableName; | ||||||
|  |  | ||||||
| import java.io.Serializable; |  | ||||||
| import java.time.LocalDate; |  | ||||||
| import java.time.LocalDateTime; |  | ||||||
| import java.util.Date; |  | ||||||
|  |  | ||||||
| import jnr.ffi.annotations.In; |  | ||||||
| import lombok.AllArgsConstructor; | import lombok.AllArgsConstructor; | ||||||
| import lombok.Data; | import lombok.Data; | ||||||
| import lombok.NoArgsConstructor; | import lombok.NoArgsConstructor; | ||||||
|  |  | ||||||
|  | import java.io.Serializable; | ||||||
|  | import java.time.LocalDateTime; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Created by skyyemperor on 2021-09-19 |  * Created by skyyemperor on 2021-09-19 | ||||||
|  * Description : |  * Description : | ||||||
| @@ -31,10 +27,10 @@ public class Job implements Serializable { | |||||||
|     private Integer jobId; |     private Integer jobId; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 基因序列数据 |      * 应用ID | ||||||
|      */ |      */ | ||||||
|     @TableField(value = "`data`") |     @TableField(value = "app_id") | ||||||
|     private String data; |     private Integer appId; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 请求参数 |      * 请求参数 | ||||||
| @@ -85,7 +81,6 @@ public class Job implements Serializable { | |||||||
|     private Integer type; |     private Integer type; | ||||||
|  |  | ||||||
|     public Job(String data, String param, String mail, Integer status, LocalDateTime requestTime, Integer type) { |     public Job(String data, String param, String mail, Integer status, LocalDateTime requestTime, Integer type) { | ||||||
|         this.data = data; |  | ||||||
|         this.param = param; |         this.param = param; | ||||||
|         this.mail = mail; |         this.mail = mail; | ||||||
|         this.status = status; |         this.status = status; | ||||||
|   | |||||||
| @@ -9,8 +9,9 @@ import com.weilab.biology.core.data.vo.result.ResultError; | |||||||
| public enum JobError implements ResultError { | public enum JobError implements ResultError { | ||||||
|     PARAM_CAN_NOT_BE_EMPTY(40100, "文本框和文件不能同时为空"), |     PARAM_CAN_NOT_BE_EMPTY(40100, "文本框和文件不能同时为空"), | ||||||
|     FILE_READ_FAIL(40101, "文件读取出错"), |     FILE_READ_FAIL(40101, "文件读取出错"), | ||||||
|     STATUS_UPDATE_FAIL(40102,"当前状态下不允许更新为指定状态"), |     STATUS_UPDATE_FAIL(40102, "当前状态下不允许更新为指定状态"), | ||||||
|     JOB_NOT_FOUND(40103,"当前状态下不允许更新为指定状态"), |     JOB_NOT_FOUND(40103, "任务不存在"), | ||||||
|  |     APP_NOT_FOUND(40104, "应用不存在"), | ||||||
|     ; |     ; | ||||||
|  |  | ||||||
|     private int code; |     private int code; | ||||||
|   | |||||||
							
								
								
									
										19
									
								
								src/main/java/com/weilab/biology/mapper/AppConfigMapper.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/main/java/com/weilab/biology/mapper/AppConfigMapper.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | package com.weilab.biology.mapper; | ||||||
|  |  | ||||||
|  | import com.weilab.biology.core.data.po.AppConfig; | ||||||
|  | import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||||||
|  | import org.apache.ibatis.annotations.Param; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * <p> | ||||||
|  |  * 应用配置信息 Mapper 接口 | ||||||
|  |  * </p> | ||||||
|  |  * | ||||||
|  |  * @author | ||||||
|  |  * @since 2023-05-05 | ||||||
|  |  */ | ||||||
|  | public interface AppConfigMapper extends BaseMapper<AppConfig> { | ||||||
|  |  | ||||||
|  |     AppConfig getAppConfigByAppName(@Param("appName") String appName); | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -14,13 +14,12 @@ import java.util.List; | |||||||
| @Mapper | @Mapper | ||||||
| public interface JobMapper extends BaseMapper<Job> { | public interface JobMapper extends BaseMapper<Job> { | ||||||
|  |  | ||||||
|     List<Job> selectRunningJobs(); |     List<Job> selectRunningJobs(@Param("appId") Integer appId); | ||||||
|  |  | ||||||
|     Job selectNextWaitingJob(); |     List<Job> selectWaitingJobs(@Param("appId") Integer appId, @Param("size") Integer size); | ||||||
|  |  | ||||||
|     List<Job> selectJobList(@Param("type") Integer type); |     List<Job> selectJobListByPage(@Param("appId") Integer appId, | ||||||
|  |                                   @Param("type") Integer type, | ||||||
|     List<Job> selectJobListByPage(@Param("type") Integer type, |  | ||||||
|                                   @Param("filterCreating") Boolean filterCreating, |                                   @Param("filterCreating") Boolean filterCreating, | ||||||
|                                   @Param("offset") Integer offset, |                                   @Param("offset") Integer offset, | ||||||
|                                   @Param("count") Integer count); |                                   @Param("count") Integer count); | ||||||
|   | |||||||
| @@ -0,0 +1,35 @@ | |||||||
|  | package com.weilab.biology.service; | ||||||
|  |  | ||||||
|  | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | ||||||
|  | import com.weilab.biology.core.data.dto.AppConfigDto; | ||||||
|  | import com.weilab.biology.core.data.po.AppConfig; | ||||||
|  | import com.weilab.biology.mapper.AppConfigMapper; | ||||||
|  | import org.apache.ibatis.annotations.Mapper; | ||||||
|  | import org.springframework.stereotype.Service; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * <p> | ||||||
|  |  * 应用配置信息 服务实现类 | ||||||
|  |  * </p> | ||||||
|  |  * | ||||||
|  |  * @author | ||||||
|  |  * @since 2023-05-05 | ||||||
|  |  */ | ||||||
|  | @Service | ||||||
|  | public class AppConfigService extends ServiceImpl<AppConfigMapper, AppConfig> { | ||||||
|  |  | ||||||
|  |     @Mapper | ||||||
|  |     private AppConfigMapper appConfigMapper; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 通过appName获取应用配置 | ||||||
|  |      * @param appName 唯一应用名 | ||||||
|  |      * @return AppConfigDto | ||||||
|  |      */ | ||||||
|  |     public AppConfigDto getAppConfig( String appName) { | ||||||
|  |        return AppConfigDto.parse(appConfigMapper.getAppConfigByAppName(appName)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -1,11 +1,15 @@ | |||||||
| package com.weilab.biology.service; | package com.weilab.biology.service; | ||||||
|  |  | ||||||
| import cn.hutool.core.io.FileUtil; | import cn.hutool.core.io.FileUtil; | ||||||
|  | import cn.hutool.core.util.StrUtil; | ||||||
| import com.alibaba.fastjson.JSON; | import com.alibaba.fastjson.JSON; | ||||||
| import com.alibaba.fastjson.JSONObject; | import com.alibaba.fastjson.JSONObject; | ||||||
|  | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | ||||||
|  | import com.weilab.biology.core.data.dto.AppConfigDto; | ||||||
| import com.weilab.biology.core.data.dto.JobDto; | import com.weilab.biology.core.data.dto.JobDto; | ||||||
| import com.weilab.biology.core.data.dto.JobLessDto; | import com.weilab.biology.core.data.dto.JobLessDto; | ||||||
| import com.weilab.biology.core.data.enums.JobStatusEnum; | import com.weilab.biology.core.data.enums.JobStatusEnum; | ||||||
|  | import com.weilab.biology.core.data.po.AppConfig; | ||||||
| import com.weilab.biology.core.data.po.Job; | import com.weilab.biology.core.data.po.Job; | ||||||
| import com.weilab.biology.core.data.vo.result.CommonError; | import com.weilab.biology.core.data.vo.result.CommonError; | ||||||
| import com.weilab.biology.core.data.vo.result.Result; | import com.weilab.biology.core.data.vo.result.Result; | ||||||
| @@ -19,9 +23,9 @@ import org.springframework.beans.factory.annotation.Autowired; | |||||||
| import org.springframework.beans.factory.annotation.Value; | import org.springframework.beans.factory.annotation.Value; | ||||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||||
| import org.springframework.transaction.annotation.Transactional; | import org.springframework.transaction.annotation.Transactional; | ||||||
|  | import org.springframework.web.multipart.MultipartFile; | ||||||
|  |  | ||||||
| import java.io.BufferedInputStream; | import java.io.IOException; | ||||||
| import java.io.File; |  | ||||||
| import java.time.LocalDateTime; | import java.time.LocalDateTime; | ||||||
| import java.time.format.DateTimeFormatter; | import java.time.format.DateTimeFormatter; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| @@ -34,22 +38,7 @@ import java.util.stream.Collectors; | |||||||
|  */ |  */ | ||||||
| @Service | @Service | ||||||
| @Slf4j | @Slf4j | ||||||
| public class JobService { | public class JobService extends ServiceImpl<JobMapper, Job> { | ||||||
|  |  | ||||||
|     @Value("${biology.python-cmd}") |  | ||||||
|     private String pythonCmd; |  | ||||||
|  |  | ||||||
|     @Value("${biology.request-path}") |  | ||||||
|     private String requestPath; |  | ||||||
|  |  | ||||||
|     @Value("${biology.result-path}") |  | ||||||
|     private String resultDataPath; |  | ||||||
|  |  | ||||||
|     @Value("${biology.log-path}") |  | ||||||
|     private String logPath; |  | ||||||
|  |  | ||||||
|     @Value("${biology.concurrent-num}") |  | ||||||
|     private Integer concurrentNum; |  | ||||||
|  |  | ||||||
|     @Autowired |     @Autowired | ||||||
|     private JobMapper jobMapper; |     private JobMapper jobMapper; | ||||||
| @@ -60,79 +49,66 @@ public class JobService { | |||||||
|     @Autowired |     @Autowired | ||||||
|     private TaskExecutorUtil<?> taskExecutorUtil; |     private TaskExecutorUtil<?> taskExecutorUtil; | ||||||
|  |  | ||||||
|     @Value("${email.subject}") |     @Autowired | ||||||
|     private String SUBJECT; |     private AppConfigService appConfigService; | ||||||
|  |  | ||||||
|     @Value("${email.content.success}") |  | ||||||
|     private String SUCCESS_EMAIL_CONTENT; |  | ||||||
|  |  | ||||||
|     @Value("${email.content.fail}") |  | ||||||
|     private String FAIL_EMAIL_CONTENT; |  | ||||||
|  |  | ||||||
|     @Value("${email.content.timeout}") |  | ||||||
|     private String TIMEOUT_EMAIL_CONTENT; |  | ||||||
|  |  | ||||||
|     @Value("${email.content.received}") |  | ||||||
|     private String RECEIVED_EMAIL_CONTENT; |  | ||||||
|  |  | ||||||
|     @Value("${email.content.running}") |  | ||||||
|     private String START_RUNNING_EMAIL_CONTENT; |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 提交job |      * 提交job | ||||||
|      */ |      */ | ||||||
|     @Transactional |     @Transactional | ||||||
|     public Result submit(String dataStr, BufferedInputStream dataStream, JSONObject param, Job job) { |     public Result submit(AppConfigDto appConfig, String dataStr, MultipartFile dataFile, JSONObject param, Job job) { | ||||||
|         jobMapper.insert(job); |         this.saveOrUpdate(job); | ||||||
|         sendEmail(job, JobStatusEnum.WAIT, job.getMail()); |  | ||||||
|  |  | ||||||
|         try { |         try { | ||||||
|             //将请求数据写入本地文件,之后向python传递文件路径参数 |             // dataStr和dataFile均为蛋白质序列,两者含义相同只保留其一,dataFile的优先级大于dataStr | ||||||
|             String dataPath = String.format(requestPath + File.separator + "job-%d-dataStr.txt", job.getJobId()); |             // 若dataFile为空,则将dataStr写入本地文件,之后向python传递文件路径参数 | ||||||
|             if (dataStream != null) { |             String dataPath = String.format(appConfig.getRequestPath() + "job-%d-dataStr.txt", job.getJobId()); | ||||||
|                 FileUtil.writeFromStream(dataStream, dataPath); |             if (dataFile != null) { | ||||||
|             } else { |                 FileUtil.writeFromStream(dataFile.getInputStream(), dataPath); | ||||||
|  |             } else if (!StrUtil.isBlank(dataStr)) { | ||||||
|                 FileUtils.writeStringToFile(dataPath, dataStr); |                 FileUtils.writeStringToFile(dataPath, dataStr); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             //将jobId和dataPath参数添加至param中 |             //将jobId和dataPath参数添加至param中 | ||||||
|             param.put("jobId", job.getJobId()); |             param.put("jobId", job.getJobId()); | ||||||
|             param.put("requestDataPath", dataPath); |             param.put("requestDataPath", dataPath); | ||||||
|             param.put("resultDataPath", resultDataPath); |             param.put("resultDataPath", appConfig.getResultPath()); | ||||||
|  |  | ||||||
|             //更新数据库param字段 |             // 更新数据库param字段 | ||||||
|             job.setParam(JSON.toJSONString(param)); |             job.setParam(JSON.toJSONString(param)); | ||||||
|             jobMapper.updateById(job); |             this.saveOrUpdate(job); | ||||||
|  |             updateJobStatus(job, JobStatusEnum.WAITING); | ||||||
|             runNextJob(); |  | ||||||
|         } catch (Exception e) { |         } catch (Exception e) { | ||||||
|             e.printStackTrace(); |             e.printStackTrace(); | ||||||
|             updateJobStatus(job.getJobId(), JobStatusEnum.FAIL); |             updateJobStatus(job, JobStatusEnum.FAIL); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return getJobInfo(job.getJobId()); |         return getJobInfo(job.getJobId()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public Result getJobInfo(Integer jobId) { |     public Result getJobInfo(Integer jobId) { | ||||||
|         Job job = jobMapper.selectById(jobId); |  | ||||||
|         if (job == null) |  | ||||||
|             return Result.getResult(CommonError.CONTENT_NOT_FOUND); |  | ||||||
|         return Result.success(JobDto.parseJob(job)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public Result updateJobStatus(Integer jobId, JobStatusEnum status) { |  | ||||||
|         return updateJobStatus(jobId, status, null); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public Result updateJobStatus(Integer jobId, JobStatusEnum status, String result) { |  | ||||||
|         System.out.println(status.getRemark()); |  | ||||||
|         Job job = jobMapper.selectById(jobId); |         Job job = jobMapper.selectById(jobId); | ||||||
|         if (job == null) { |         if (job == null) { | ||||||
|             return Result.getResult(CommonError.CONTENT_NOT_FOUND); |             return Result.getResult(CommonError.CONTENT_NOT_FOUND); | ||||||
|         } |         } | ||||||
|  |         return Result.success(JobDto.parseJob(job)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public Result updateJobStatus(Job job, JobStatusEnum status) { | ||||||
|  |         return updateJobStatus(job, status, null); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 更新任务状态 | ||||||
|  |      * | ||||||
|  |      * @param job    任务 | ||||||
|  |      * @param status 状态 | ||||||
|  |      * @param result 任务运行结果 | ||||||
|  |      */ | ||||||
|  |     public Result updateJobStatus(Job job, JobStatusEnum status, String result) { | ||||||
|         switch (status) { |         switch (status) { | ||||||
|             case WAIT: |             case WAITING: | ||||||
|  |             case CREATING: | ||||||
|                 break; |                 break; | ||||||
|             case SUCCESS: |             case SUCCESS: | ||||||
|                 job.setCompleteTime(LocalDateTime.now()); |                 job.setCompleteTime(LocalDateTime.now()); | ||||||
| @@ -141,7 +117,7 @@ public class JobService { | |||||||
|             case FAIL: |             case FAIL: | ||||||
|             case TIMEOUT: |             case TIMEOUT: | ||||||
|                 if (!job.getStatus().equals(JobStatusEnum.RUNNING.getKey()) |                 if (!job.getStatus().equals(JobStatusEnum.RUNNING.getKey()) | ||||||
|                         && !job.getStatus().equals(JobStatusEnum.REQED.getKey())){ |                         && !job.getStatus().equals(JobStatusEnum.REQED.getKey())) { | ||||||
|                     return Result.getResult(JobError.STATUS_UPDATE_FAIL); |                     return Result.getResult(JobError.STATUS_UPDATE_FAIL); | ||||||
|                 } |                 } | ||||||
|                 job.setCompleteTime(LocalDateTime.now()); |                 job.setCompleteTime(LocalDateTime.now()); | ||||||
| @@ -150,7 +126,7 @@ public class JobService { | |||||||
|                 if (!job.getStatus().equals(JobStatusEnum.REQED.getKey())) { |                 if (!job.getStatus().equals(JobStatusEnum.REQED.getKey())) { | ||||||
|                     return Result.getResult(JobError.STATUS_UPDATE_FAIL); |                     return Result.getResult(JobError.STATUS_UPDATE_FAIL); | ||||||
|                 } |                 } | ||||||
|                 job.setCreateTime(LocalDateTime.now()); |                 job.setRequestTime(LocalDateTime.now()); | ||||||
|                 break; |                 break; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -158,104 +134,91 @@ public class JobService { | |||||||
|         jobMapper.updateById(job); |         jobMapper.updateById(job); | ||||||
|  |  | ||||||
|         sendEmail(job, status, job.getMail()); |         sendEmail(job, status, job.getMail()); | ||||||
|         runNextJob(); |  | ||||||
|  |  | ||||||
|         return getJobInfo(jobId); |         return getJobInfo(job.getJobId()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public Result getJobList(Integer type) { |     public Result getJobList(Integer appId, Integer type, Boolean filterCreating, Integer page, Integer size) { | ||||||
|         List<Job> jobs = jobMapper.selectJobList(type); |         List<Job> jobs = jobMapper.selectJobListByPage(appId, type, filterCreating, (page - 1) * size, size); | ||||||
|         return Result.success(jobs.stream().map(JobLessDto::parseJob).collect(Collectors.toList())); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public Result getJobList(Integer type, Boolean filterCreating, Integer page, Integer size) { |  | ||||||
|         List<Job> jobs = jobMapper.selectJobListByPage(type, filterCreating, (page - 1) * size, size); |  | ||||||
|         return Result.success(jobs.stream().map(JobLessDto::parseJob).collect(Collectors.toList())); |         return Result.success(jobs.stream().map(JobLessDto::parseJob).collect(Collectors.toList())); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 运行下一个job |      * 运行job | ||||||
|      */ |      */ | ||||||
|     private synchronized void runNextJob() { |     public synchronized void runJob() { | ||||||
|         Job nextJob = null; |         List<AppConfigDto> appConfigList = appConfigService.list().stream() | ||||||
|  |                 .map(AppConfigDto::parse) | ||||||
|  |                 .collect(Collectors.toList()); | ||||||
|  |         appConfigList.forEach(appConfig -> { | ||||||
|  |             //并发数小于concurrentNum,运行job | ||||||
|  |             int size = appConfig.getConcurrentNum() - jobMapper.selectRunningJobs(appConfig.getAppId()).size(); | ||||||
|  |             if (size <= 0) { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             jobMapper.selectWaitingJobs(appConfig.getAppId(), size) | ||||||
|  |                     .forEach(job -> runJob(appConfig, job)); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void runJob(AppConfigDto appConfig, Job job) { | ||||||
|         try { |         try { | ||||||
|             //并发数小于concurrentNum,运行该job |             String logFilePath = String.format(appConfig.getLogPath() + "task-log-%s.txt", job.getJobId()); | ||||||
|             if (jobMapper.selectRunningJobs().size() < concurrentNum) { |             String cmd = String.format("%s -setting '%s' >> %s 2>&1", appConfig.getCmd(), job.getParam(), logFilePath); | ||||||
|                 if ((nextJob = jobMapper.selectNextWaitingJob()) != null) { |             String[] cmds = new String[]{"/bin/sh", "-c", cmd}; | ||||||
|                     //更新job状态 |             Runtime.getRuntime().exec(cmds); | ||||||
|                     nextJob.setStatus(JobStatusEnum.REQED.getKey()); |  | ||||||
|                     jobMapper.updateById(nextJob); |  | ||||||
|  |  | ||||||
|                     waitRunning(nextJob.getJobId()); |  | ||||||
|  |  | ||||||
|                     String logFilePath = String.format(logPath + File.separator + "task-log-%s.txt", nextJob.getJobId()); |  | ||||||
|                     String cmd = String.format("%s -setting '%s' >> %s 2>&1", pythonCmd, nextJob.getParam(), logFilePath); |  | ||||||
|  |  | ||||||
|             log.info("执行命令: " + cmd); |             log.info("执行命令: " + cmd); | ||||||
|  |  | ||||||
|                     String[] cmds = new String[]{"/bin/sh", "-c", cmd}; |             // 更新job状态 | ||||||
|  |             updateJobStatus(job, JobStatusEnum.REQED); | ||||||
|  |  | ||||||
|                     Runtime.getRuntime().exec(cmds); |             // 异步检测超时 | ||||||
|                 } |             asyncScheduleTask(appConfig, job.getJobId()); | ||||||
|             } |  | ||||||
|         } catch (Exception e) { |         } catch (Exception e) { | ||||||
|             e.printStackTrace(); |             e.printStackTrace(); | ||||||
|             if (nextJob != null) { |             updateJobStatus(job, JobStatusEnum.FAIL); | ||||||
|                 nextJob.setStatus(JobStatusEnum.FAIL.getKey()); |  | ||||||
|                 jobMapper.updateById(nextJob); |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 等待运行 |      * 开启异步定时任务,校验超时任务 | ||||||
|      */ |      */ | ||||||
|     private void waitRunning(Integer jobId) { |     private void asyncScheduleTask(AppConfigDto appConfig, Integer jobId) { | ||||||
|         //等待120秒,检查是否已运行 |         //等待120秒,检查是否已运行 | ||||||
|         taskExecutorUtil.schedule(() -> { |         taskExecutorUtil.schedule(() -> { | ||||||
|             Job job = jobMapper.selectById(jobId); |             Job job = jobMapper.selectById(jobId); | ||||||
|             if (job.getStatus().equals(JobStatusEnum.REQED.getKey())) { |             if (job.getStatus().equals(JobStatusEnum.REQED.getKey())) { | ||||||
|                 updateJobStatus(jobId, JobStatusEnum.FAIL); |                 updateJobStatus(job, JobStatusEnum.FAIL); | ||||||
|             } |             } | ||||||
|         }, 120, TimeUnit.SECONDS); |         }, 120, TimeUnit.SECONDS); | ||||||
|  |  | ||||||
|         //等待14小时,查看是否执行完成 |         //等待一段时间后,查看是否执行完成 | ||||||
|         taskExecutorUtil.schedule(() -> { |         taskExecutorUtil.schedule(() -> { | ||||||
|             Job job = jobMapper.selectById(jobId); |             Job job = jobMapper.selectById(jobId); | ||||||
|             if (job.getStatus().equals(JobStatusEnum.RUNNING.getKey())) { |             if (job.getStatus().equals(JobStatusEnum.RUNNING.getKey())) { | ||||||
|                 updateJobStatus(jobId, JobStatusEnum.TIMEOUT); |                 updateJobStatus(job, JobStatusEnum.TIMEOUT); | ||||||
|             } |             } | ||||||
|         }, 14, TimeUnit.HOURS); |         }, appConfig.getTimeout(), TimeUnit.MINUTES); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void sendEmail(Job job, JobStatusEnum status, String mail) { |     private void sendEmail(Job job, JobStatusEnum status, String mail) { | ||||||
|  |         AppConfigDto appConfig = AppConfigDto.parse(appConfigService.getById(job.getAppId())); | ||||||
|  |         if (appConfig == null) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         // 多个参数 |         // 多个参数 | ||||||
|         String param1 = job.getRequestTime().format(DateTimeFormatter.ofPattern("yyyyMMdd")) + job.getJobId(); |         String param1 = job.getRequestTime().format(DateTimeFormatter.ofPattern("yyyyMMdd")) + job.getJobId(); | ||||||
|         String param2 = param1; |         String param2 = param1; | ||||||
|  |  | ||||||
|         String content = null; |         String content = appConfig.getEmailTemplate().getString(status.getRemark()); | ||||||
|         switch (status) { |         String subject = appConfig.getEmailTemplate().getString("subject"); | ||||||
|             case WAIT: |         if (StrUtil.isBlank(content) || StrUtil.isBlank(subject)) { | ||||||
|                 content = RECEIVED_EMAIL_CONTENT; |             return; | ||||||
|                 break; |  | ||||||
|             case SUCCESS: |  | ||||||
|                 content = SUCCESS_EMAIL_CONTENT; |  | ||||||
|                 break; |  | ||||||
|             case FAIL: |  | ||||||
|                 content = FAIL_EMAIL_CONTENT; |  | ||||||
|                 break; |  | ||||||
|             case TIMEOUT: |  | ||||||
|                 content = TIMEOUT_EMAIL_CONTENT; |  | ||||||
|                 break; |  | ||||||
|             case RUNNING: |  | ||||||
|                 content = START_RUNNING_EMAIL_CONTENT; |  | ||||||
|                 break; |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         mailUtil.send(mail, String.format(subject, param1), String.format(content, param1, param2)); | ||||||
|         if (content != null) { |  | ||||||
|             mailUtil.send(mail, String.format(SUBJECT, param1), String.format(content, param1, param2)); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										28
									
								
								src/main/resources/mapper/AppConfigMapper.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/main/resources/mapper/AppConfigMapper.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | ||||||
|  | <mapper namespace="com.weilab.biology.mapper.AppConfigMapper"> | ||||||
|  |  | ||||||
|  |     <!-- 通用查询映射结果 --> | ||||||
|  |     <resultMap id="BaseResultMap" type="com.weilab.biology.core.data.po.AppConfig"> | ||||||
|  |         <id column="app_id" property="appId"/> | ||||||
|  |         <result column="app_name" property="appName"/> | ||||||
|  |         <result column="concurrent_num" property="concurrentNum"/> | ||||||
|  |         <result column="cmd" property="cmd"/> | ||||||
|  |         <result column="timeout" property="timeout"/> | ||||||
|  |         <result column="local_path" property="localPath"/> | ||||||
|  |         <result column="email_template" property="emailTemplate"/> | ||||||
|  |     </resultMap> | ||||||
|  |  | ||||||
|  |     <sql id="AppConfigSql"> | ||||||
|  |         SELECT app_id, app_name, concurrent_num, cmd, timeout, local_path, email_template | ||||||
|  |         FROM app_config | ||||||
|  |     </sql> | ||||||
|  |  | ||||||
|  |     <select id="getAppConfigByAppName" resultType="com.weilab.biology.core.data.po.AppConfig" | ||||||
|  |             parameterType="java.lang.String"> | ||||||
|  |         <include refid="AppConfigSql"/> | ||||||
|  |         WHERE app_name = #{appName} | ||||||
|  |     </select> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | </mapper> | ||||||
| @@ -3,7 +3,6 @@ | |||||||
| <mapper namespace="com.weilab.biology.mapper.JobMapper"> | <mapper namespace="com.weilab.biology.mapper.JobMapper"> | ||||||
|     <resultMap id="BaseResultMap" type="com.weilab.biology.core.data.po.Job"> |     <resultMap id="BaseResultMap" type="com.weilab.biology.core.data.po.Job"> | ||||||
|         <id column="job_id" jdbcType="INTEGER" property="jobId"/> |         <id column="job_id" jdbcType="INTEGER" property="jobId"/> | ||||||
|         <result column="data" jdbcType="LONGVARCHAR" property="data"/> |  | ||||||
|         <result column="param" jdbcType="VARCHAR" property="param"/> |         <result column="param" jdbcType="VARCHAR" property="param"/> | ||||||
|         <result column="mail" jdbcType="VARCHAR" property="mail"/> |         <result column="mail" jdbcType="VARCHAR" property="mail"/> | ||||||
|         <result column="result" jdbcType="LONGVARCHAR" property="result"/> |         <result column="result" jdbcType="LONGVARCHAR" property="result"/> | ||||||
| @@ -15,15 +14,14 @@ | |||||||
|     </resultMap> |     </resultMap> | ||||||
|     <sql id="JobSql"> |     <sql id="JobSql"> | ||||||
|         SELECT job_id, |         SELECT job_id, | ||||||
|                `data`, |  | ||||||
|                param, |                param, | ||||||
|                mail, |                mail, | ||||||
|                result, |                `result`, | ||||||
|                `status`, |                `status`, | ||||||
|                request_time, |                request_time, | ||||||
|                create_time, |                create_time, | ||||||
|                complete_time, |                complete_time, | ||||||
|                type |                `type` | ||||||
|         FROM job |         FROM job | ||||||
|     </sql> |     </sql> | ||||||
|     <sql id="JobLessSql"> |     <sql id="JobLessSql"> | ||||||
| @@ -32,34 +30,29 @@ | |||||||
|                request_time, |                request_time, | ||||||
|                create_time, |                create_time, | ||||||
|                complete_time, |                complete_time, | ||||||
|                type |                `type` | ||||||
|         FROM job |         FROM job | ||||||
|     </sql> |     </sql> | ||||||
|     <select id="selectRunningJobs" resultMap="BaseResultMap"> |     <select id="selectRunningJobs" resultMap="BaseResultMap"> | ||||||
|         <include refid="JobSql"/> |         <include refid="JobSql"/> | ||||||
|         WHERE status = '${@com.weilab.biology.core.data.enums.JobStatusEnum@RUNNING.getKey()}' |         WHERE app_id = #{appId} | ||||||
|            OR status = '${@com.weilab.biology.core.data.enums.JobStatusEnum@REQED.getKey()}' |         AND (status = '${@com.weilab.biology.core.data.enums.JobStatusEnum@RUNNING.getKey()}' | ||||||
|  |         OR status = '${@com.weilab.biology.core.data.enums.JobStatusEnum@REQED.getKey()}') | ||||||
|     </select> |     </select> | ||||||
|     <select id="selectNextWaitingJob" resultMap="BaseResultMap"> |  | ||||||
|  |     <select id="selectWaitingJobs" resultMap="BaseResultMap"> | ||||||
|         <include refid="JobSql"/> |         <include refid="JobSql"/> | ||||||
|         WHERE status = '${@com.weilab.biology.core.data.enums.JobStatusEnum@WAIT.getKey()}' |         WHERE app_id = #{appId} | ||||||
|         ORDER BY request_time LIMIT 1 |         AND status = '${@com.weilab.biology.core.data.enums.JobStatusEnum@WAITING.getKey()}' | ||||||
|     </select> |         ORDER BY create_time LIMIT #{size} | ||||||
|     <select id="selectJobList" resultMap="BaseResultMap"> |  | ||||||
|         <include refid="JobLessSql"/> |  | ||||||
|         <where> |  | ||||||
|             <if test="type != null"> |  | ||||||
|                 AND type = #{type} |  | ||||||
|             </if> |  | ||||||
|             AND request_time > DATE_SUB(CURDATE(), INTERVAL 3 MONTH) |  | ||||||
|         </where> |  | ||||||
|         ORDER BY job_id DESC |  | ||||||
|         <!--        LIMIT #{count}--> |  | ||||||
|     </select> |     </select> | ||||||
|  |  | ||||||
|     <select id="selectJobListByPage" resultMap="BaseResultMap"> |     <select id="selectJobListByPage" resultMap="BaseResultMap"> | ||||||
|         <include refid="JobLessSql"/> |         <include refid="JobLessSql"/> | ||||||
|         <where> |         <where> | ||||||
|  |             <if test="appId != null"> | ||||||
|  |                 AND app_id = #{appId} | ||||||
|  |             </if> | ||||||
|             <if test="type != null"> |             <if test="type != null"> | ||||||
|                 AND type = #{type} |                 AND type = #{type} | ||||||
|             </if> |             </if> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user