JobBriefingServiceImpl.java 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. package net.yyc.quartz.service.impl;
  2. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  3. import lombok.RequiredArgsConstructor;
  4. import lombok.extern.slf4j.Slf4j;
  5. import net.yyc.quartz.entity.JobBriefing;
  6. import net.yyc.quartz.entity.SysJob;
  7. import net.yyc.quartz.mapper.JobBriefingMapper;
  8. import net.yyc.quartz.service.JobBriefingService;
  9. import net.yyc.quartz.service.SysJobService;
  10. import net.yyc.quartz.util.DateUtils;
  11. import org.springframework.stereotype.Service;
  12. import java.time.LocalDate;
  13. import java.time.LocalDateTime;
  14. import java.time.LocalTime;
  15. import java.time.format.DateTimeFormatter;
  16. import java.util.*;
  17. import java.util.stream.Collectors;
  18. /**
  19. * 每日简报服务实现
  20. */
  21. @Slf4j
  22. @Service
  23. @RequiredArgsConstructor
  24. public class JobBriefingServiceImpl implements JobBriefingService {
  25. private final JobBriefingMapper jobBriefingMapper;
  26. private final SysJobService sysJobService;
  27. private static final DateTimeFormatter defaultDateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
  28. @Override
  29. public JobBriefing generateBriefing(LocalDate date) {
  30. LocalDateTime startTime = date.atStartOfDay();
  31. LocalDateTime endTime = date.atTime(LocalTime.MAX);
  32. // 1. 获取昨日执行的任务列表
  33. List<Integer> executedJobIds = jobBriefingMapper.selectExecutedJobIds(startTime, endTime);
  34. // 2. 获取非删除且非暂停的任务(1已发布 2运行中)
  35. LambdaQueryWrapper<SysJob> queryWrapper = new LambdaQueryWrapper<>();
  36. queryWrapper.in(SysJob::getJobStatus, "1", "2");
  37. List<SysJob> runningJobList = sysJobService.list(queryWrapper);
  38. if (runningJobList == null) {
  39. runningJobList = Collections.emptyList();
  40. }
  41. // 3. 任务ID列表
  42. Set<Integer> allJobIds = runningJobList.stream()
  43. .map(SysJob::getJobId)
  44. .collect(Collectors.toSet());
  45. // 5. 查询昨日执行统计
  46. List<Map<String, Object>> statSummary = jobBriefingMapper.selectJobStatSummary(startTime, endTime);
  47. Map<Integer, Map<String, Object>> statMap = new HashMap<>();
  48. for (Map<String, Object> stat : statSummary) {
  49. Integer jobId = ((Number) stat.get("job_id")).intValue();
  50. statMap.put(jobId, stat);
  51. }
  52. // 6. 构建任务统计列表
  53. List<JobBriefing.JobStatInfo> jobStats = new ArrayList<>();
  54. for (SysJob sysJob : runningJobList) {
  55. Map<String, Object> stat = statMap.get(sysJob.getJobId());
  56. String jobName = sysJob.getJobName();
  57. String jobGroup = sysJob.getJobGroup();
  58. int execCount = 0, successCount = 0, failCount = 0;
  59. long avgExecuteTime = 0;
  60. String lastExecStatus = null;
  61. String exceptionInfo = null;
  62. if (stat != null) {
  63. execCount = ((Number) stat.get("execCount")).intValue();
  64. successCount = ((Number) stat.get("successCount")).intValue();
  65. failCount = ((Number) stat.get("failCount")).intValue();
  66. Object avgObj = stat.get("avgExecuteTime");
  67. if (avgObj != null) {
  68. avgExecuteTime = ((Number) avgObj).longValue();
  69. }
  70. }
  71. // 查询最新执行记录
  72. Map<String, Object> lastLog = jobBriefingMapper.selectLastExecLog(sysJob.getJobId(), LocalDateTime.now());
  73. if (lastLog != null) {
  74. lastExecStatus = "1".equals(String.valueOf(lastLog.get("job_log_status"))) ? "失败" : "成功";
  75. Object exInfo = lastLog.get("exception_info");
  76. if (exInfo != null && !"null".equals(String.valueOf(exInfo))) {
  77. exceptionInfo = String.valueOf(exInfo);
  78. if (exceptionInfo.length() > 200) {
  79. exceptionInfo = exceptionInfo.substring(0, 200) + "...";
  80. }
  81. }
  82. }
  83. double successRate = execCount > 0 ? (double) successCount / execCount * 100 : 0;
  84. jobStats.add(JobBriefing.JobStatInfo.builder()
  85. .jobId(sysJob.getJobId())
  86. .jobName(jobName)
  87. .jobGroup(jobGroup)
  88. .jobStatus(sysJob.getJobStatus())
  89. .nextExecuteTime(sysJob.getNextTime())
  90. .execCount(execCount)
  91. .successCount(successCount)
  92. .failCount(failCount)
  93. .successRate(Math.round(successRate * 100) / 100.0)
  94. .avgExecuteTime(avgExecuteTime)
  95. .lastExecuteTime(sysJob.getPreviousTime())
  96. .lastExecStatus(lastExecStatus)
  97. .exceptionInfo(exceptionInfo)
  98. .build());
  99. }
  100. // 按任务名称排序
  101. jobStats.sort(Comparator.comparing(JobBriefing.JobStatInfo::getJobName));
  102. // 7. 检测错过执行的任务
  103. List<JobBriefing.MissedJobInfo> missedJobs = detectMissedJobs(date, startTime, endTime, executedJobIds, runningJobList);
  104. return JobBriefing.builder()
  105. .reportDate(date)
  106. .jobStats(jobStats)
  107. .missedJobs(missedJobs)
  108. .generatedAt(LocalDateTime.now())
  109. .build();
  110. }
  111. @Override
  112. public JobBriefing generateYesterdayBriefing() {
  113. return generateBriefing(LocalDate.now().minusDays(1));
  114. }
  115. /**
  116. * 检测错过执行的任务
  117. * 条件:任务状态=RUNNING(2) 且 next_time已过 且 昨日无执行记录
  118. */
  119. private List<JobBriefing.MissedJobInfo> detectMissedJobs(LocalDate date,
  120. LocalDateTime startTime,
  121. LocalDateTime endTime,
  122. List<Integer> executedJobIds,
  123. List<SysJob> runningJobList) {
  124. List<JobBriefing.MissedJobInfo> missed = new ArrayList<>();
  125. Set<Integer> executedSet = new HashSet<>(executedJobIds);
  126. LocalDateTime now = LocalDateTime.now();
  127. for (SysJob job : runningJobList) {
  128. // 检查昨日是否有执行记录
  129. if (executedSet.contains(job.getJobId())) {
  130. continue;
  131. }
  132. // 检查 next_time 是否已过
  133. if (job.getNextTime() != null && job.getNextTime().isBefore(now)) {
  134. missed.add(JobBriefing.MissedJobInfo.builder()
  135. .jobName(job.getJobName())
  136. .jobGroup(job.getJobGroup())
  137. .nextExecuteTime(job.getNextTime())
  138. .remark("下次执行时间已过,请检查任务调度")
  139. .build());
  140. }
  141. }
  142. return missed;
  143. }
  144. }