1 changed files with 133 additions and 0 deletions
@ -0,0 +1,133 @@ |
|||
package com.project.exam.domain.job; |
|||
|
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
|||
import com.project.exam.domain.entity.ExamRecordEntity; |
|||
import com.project.exam.mapper.ExamRecordMapper; |
|||
import com.project.task.domain.entity.TaskEntity; |
|||
import com.project.task.domain.entity.TaskUserEntity; |
|||
import com.project.task.mapper.TaskMapper; |
|||
import com.project.task.mapper.TaskUserMapper; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.scheduling.annotation.Scheduled; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import java.util.Date; |
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 考试异常处理定时任务 |
|||
* 处理考试任务截止或考试时间结束时未提交的考试记录 |
|||
*/ |
|||
@Service |
|||
@Slf4j |
|||
public class examHandleJob { |
|||
|
|||
@Autowired |
|||
private ExamRecordMapper examRecordMapper; |
|||
|
|||
@Autowired |
|||
private TaskMapper taskMapper; |
|||
|
|||
@Autowired |
|||
private TaskUserMapper taskUserMapper; |
|||
|
|||
/** |
|||
* 考试超时缓冲时间(秒),只处理超过这个时间的超时考试 |
|||
*/ |
|||
private static final long EXAM_TIMEOUT_BUFFER_SECONDS = 10; |
|||
|
|||
/** |
|||
* 每小时执行一次,处理考试时间结束但未提交的考试记录 |
|||
*/ |
|||
@Scheduled(cron = "0 0 * * * ?") |
|||
public void handleUnsubmittedExams() { |
|||
log.info(">>> [考试异常处理任务] 启动执行..."); |
|||
|
|||
try { |
|||
Date now = new Date(); |
|||
|
|||
// 查询所有未提交的考试记录
|
|||
LambdaQueryWrapper<ExamRecordEntity> examWrapper = new LambdaQueryWrapper<>(); |
|||
examWrapper.isNull(ExamRecordEntity::getSubmitTime); |
|||
|
|||
List<ExamRecordEntity> unsubmittedRecords = examRecordMapper.selectList(examWrapper); |
|||
|
|||
if (unsubmittedRecords.isEmpty()) { |
|||
log.info(">>> [考试异常处理任务] 没有未提交的考试记录"); |
|||
return; |
|||
} |
|||
|
|||
log.info(">>> [考试异常处理任务] 发现 {} 条未提交的考试记录,开始检查考试时间", unsubmittedRecords.size()); |
|||
|
|||
// 处理每条未提交的考试记录
|
|||
for (ExamRecordEntity examRecord : unsubmittedRecords) { |
|||
handleUnsubmittedExamRecord(examRecord, now); |
|||
} |
|||
|
|||
log.info(">>> [考试异常处理任务] 执行完毕"); |
|||
} catch (Exception e) { |
|||
log.error(">>> [考试异常处理任务] 执行异常", e); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 处理单条未提交的考试记录 |
|||
* 如果考试时间已结束超过缓冲时间,则设置为未通过,提交时间为考试结束时间 |
|||
*/ |
|||
private void handleUnsubmittedExamRecord(ExamRecordEntity examRecord, Date now) { |
|||
try { |
|||
// 获取关联的 TaskUserEntity,从中获取考试开始时间
|
|||
TaskUserEntity taskUser = taskUserMapper.selectById(examRecord.getTaskUserId()); |
|||
|
|||
if (taskUser == null) { |
|||
log.warn(">>> [考试异常处理任务] 找不到 TaskUserEntity,id: {}", examRecord.getTaskUserId()); |
|||
return; |
|||
} |
|||
|
|||
// 获取考试任务的时长配置
|
|||
TaskEntity task = taskMapper.selectById(taskUser.getTaskId()); |
|||
|
|||
if (task == null) { |
|||
log.warn(">>> [考试异常处理任务] 找不到 TaskEntity,id: {}", taskUser.getTaskId()); |
|||
return; |
|||
} |
|||
|
|||
// 计算考试结束时间 = 开始时间 + 考试时长(分钟)
|
|||
Date examEndTime = new Date(examRecord.getStartTime().getTime() + (long) task.getDuration() * 60 * 1000); |
|||
|
|||
// 计算考试结束时间 + 缓冲时间
|
|||
Date examTimeoutThreshold = new Date(examEndTime.getTime() + EXAM_TIMEOUT_BUFFER_SECONDS * 1000); |
|||
|
|||
// 判断考试是否已经超时(超过缓冲时间)
|
|||
if (examTimeoutThreshold.after(now)) { |
|||
log.debug(">>> [考试异常处理任务] 考试记录 {} 的考试时间未超过缓冲时间,跳过。考试结束时间: {},缓冲阈值: {},当前时间: {}", |
|||
examRecord.getId(), examEndTime, examTimeoutThreshold, now); |
|||
return; |
|||
} |
|||
|
|||
log.info(">>> [考试异常处理任务] 考试记录 {} 已超时 {} 秒以上,将其设置为未通过。考试开始: {},时长: {} 分钟,结束: {},当前: {}", |
|||
examRecord.getId(), EXAM_TIMEOUT_BUFFER_SECONDS, examRecord.getStartTime(), task.getDuration(), examEndTime, now); |
|||
|
|||
// 更新未提交的考试记录 - 使用条件更新防止并发问题
|
|||
// 只更新提交时间仍为null的记录,防止用户刚提交时的竞态条件
|
|||
LambdaUpdateWrapper<ExamRecordEntity> updateWrapper = new LambdaUpdateWrapper<>(); |
|||
updateWrapper.eq(ExamRecordEntity::getId, examRecord.getId()) |
|||
.isNull(ExamRecordEntity::getSubmitTime) // 再次检查提交时间是否为null
|
|||
.set(ExamRecordEntity::getPass, false) // 设置为未通过
|
|||
.set(ExamRecordEntity::getSubmitTime, examEndTime); // 提交时间设置为考试结束时间
|
|||
|
|||
int updateCount = examRecordMapper.update(null, updateWrapper); |
|||
|
|||
if (updateCount > 0) { |
|||
log.info(">>> [考试异常处理任务] 考试记录 {} 更新成功", examRecord.getId()); |
|||
} else { |
|||
log.warn(">>> [考试异常处理任务] 考试记录 {} 更新失败,可能已被其他操作修改(如用户已提交)", examRecord.getId()); |
|||
} |
|||
|
|||
} catch (Exception e) { |
|||
log.error(">>> [考试异常处理任务] 处理考试记录 {} 异常", examRecord.getId(), e); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue