JobBriefingServiceImpl.java 7.3 KB

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