package net.yyc.quartz.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import net.yyc.quartz.entity.JobBriefing; import net.yyc.quartz.entity.SysJob; import net.yyc.quartz.mapper.JobBriefingMapper; import net.yyc.quartz.service.JobBriefingService; import net.yyc.quartz.service.SysJobService; import net.yyc.quartz.util.DateUtils; import org.springframework.stereotype.Service; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.stream.Collectors; /** * 每日简报服务实现 */ @Slf4j @Service @RequiredArgsConstructor public class JobBriefingServiceImpl implements JobBriefingService { private final JobBriefingMapper jobBriefingMapper; private final SysJobService sysJobService; private static final DateTimeFormatter defaultDateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); @Override public JobBriefing generateBriefing(LocalDate date) { LocalDateTime startTime = date.atStartOfDay(); LocalDateTime endTime = date.atTime(LocalTime.MAX); // 1. 获取昨日执行的任务列表 List executedJobIds = jobBriefingMapper.selectExecutedJobIds(startTime, endTime); // 2. 获取非删除且非暂停的任务(1已发布 2运行中) LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.in(SysJob::getJobStatus, "1", "2"); List runningJobList = sysJobService.list(queryWrapper); if (runningJobList == null) { runningJobList = Collections.emptyList(); } // 3. 任务ID列表 Set allJobIds = runningJobList.stream() .map(SysJob::getJobId) .collect(Collectors.toSet()); // 5. 查询昨日执行统计 List> statSummary = jobBriefingMapper.selectJobStatSummary(startTime, endTime); Map> statMap = new HashMap<>(); for (Map stat : statSummary) { Integer jobId = ((Number) stat.get("job_id")).intValue(); statMap.put(jobId, stat); } // 6. 构建任务统计列表 List jobStats = new ArrayList<>(); for (SysJob sysJob : runningJobList) { Map stat = statMap.get(sysJob.getJobId()); String jobName = sysJob.getJobName(); String jobGroup = sysJob.getJobGroup(); int execCount = 0, successCount = 0, failCount = 0; long avgExecuteTime = 0; String lastExecStatus = null; String exceptionInfo = null; if (stat != null) { execCount = ((Number) stat.get("execCount")).intValue(); successCount = ((Number) stat.get("successCount")).intValue(); failCount = ((Number) stat.get("failCount")).intValue(); Object avgObj = stat.get("avgExecuteTime"); if (avgObj != null) { avgExecuteTime = ((Number) avgObj).longValue(); } } // 查询最新执行记录 Map lastLog = jobBriefingMapper.selectLastExecLog(sysJob.getJobId(), LocalDateTime.now()); if (lastLog != null) { lastExecStatus = "1".equals(String.valueOf(lastLog.get("job_log_status"))) ? "失败" : "成功"; Object exInfo = lastLog.get("exception_info"); if (exInfo != null && !"null".equals(String.valueOf(exInfo))) { exceptionInfo = String.valueOf(exInfo); if (exceptionInfo.length() > 200) { exceptionInfo = exceptionInfo.substring(0, 200) + "..."; } } } double successRate = execCount > 0 ? (double) successCount / execCount * 100 : 0; jobStats.add(JobBriefing.JobStatInfo.builder() .jobId(sysJob.getJobId()) .jobName(jobName) .jobGroup(jobGroup) .jobStatus(sysJob.getJobStatus()) .nextExecuteTime(sysJob.getNextTime()) .execCount(execCount) .successCount(successCount) .failCount(failCount) .successRate(Math.round(successRate * 100) / 100.0) .avgExecuteTime(avgExecuteTime) .lastExecuteTime(sysJob.getPreviousTime()) .lastExecStatus(lastExecStatus) .exceptionInfo(exceptionInfo) .build()); } // 按任务名称排序 jobStats.sort(Comparator.comparing(JobBriefing.JobStatInfo::getJobName)); // 7. 检测错过执行的任务 List missedJobs = detectMissedJobs(date, startTime, endTime, executedJobIds, runningJobList); return JobBriefing.builder() .reportDate(date) .jobStats(jobStats) .missedJobs(missedJobs) .generatedAt(LocalDateTime.now()) .build(); } @Override public JobBriefing generateYesterdayBriefing() { return generateBriefing(LocalDate.now().minusDays(1)); } /** * 检测错过执行的任务 * 条件:任务状态=RUNNING(2) 且 next_time已过 且 昨日无执行记录 */ private List detectMissedJobs(LocalDate date, LocalDateTime startTime, LocalDateTime endTime, List executedJobIds, List runningJobList) { List missed = new ArrayList<>(); Set executedSet = new HashSet<>(executedJobIds); LocalDateTime now = LocalDateTime.now(); for (SysJob job : runningJobList) { // 检查昨日是否有执行记录 if (executedSet.contains(job.getJobId())) { continue; } // 检查 next_time 是否已过 if (job.getNextTime() != null && job.getNextTime().isBefore(now)) { missed.add(JobBriefing.MissedJobInfo.builder() .jobName(job.getJobName()) .jobGroup(job.getJobGroup()) .nextExecuteTime(job.getNextTime()) .remark("下次执行时间已过,请检查任务调度") .build()); } } return missed; } }