|
@@ -1,148 +0,0 @@
|
|
|
-package com.qmth.exam.reserve.job;
|
|
|
-
|
|
|
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
-import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
|
-import com.qmth.boot.core.concurrent.service.ConcurrentService;
|
|
|
-import com.qmth.exam.reserve.bean.apply.ApplyRecordCacheBean;
|
|
|
-import com.qmth.exam.reserve.cache.CacheConstants;
|
|
|
-import com.qmth.exam.reserve.cache.RedisClient;
|
|
|
-import com.qmth.exam.reserve.cache.impl.ApplyTaskCacheService;
|
|
|
-import com.qmth.exam.reserve.entity.StudentApplyEntity;
|
|
|
-import com.qmth.exam.reserve.enums.EventType;
|
|
|
-import com.qmth.exam.reserve.service.OperateLogService;
|
|
|
-import com.qmth.exam.reserve.service.StudentApplyService;
|
|
|
-import com.qmth.exam.reserve.util.JsonHelper;
|
|
|
-import org.redisson.api.RLock;
|
|
|
-import org.redisson.api.RQueue;
|
|
|
-import org.slf4j.Logger;
|
|
|
-import org.slf4j.LoggerFactory;
|
|
|
-import org.springframework.beans.factory.annotation.Autowired;
|
|
|
-import org.springframework.scheduling.annotation.Scheduled;
|
|
|
-import org.springframework.stereotype.Component;
|
|
|
-
|
|
|
-@Component
|
|
|
-public class StudentApplyRecordJob {
|
|
|
-
|
|
|
- private static final Logger log = LoggerFactory.getLogger(StudentApplyRecordJob.class);
|
|
|
-
|
|
|
- @Autowired
|
|
|
- private StudentApplyService studentApplyService;
|
|
|
-
|
|
|
- @Autowired
|
|
|
- private OperateLogService operateLogService;
|
|
|
-
|
|
|
- @Autowired
|
|
|
- private ApplyTaskCacheService applyTaskCacheService;
|
|
|
-
|
|
|
- @Autowired
|
|
|
- private ConcurrentService concurrentService;
|
|
|
-
|
|
|
- @Autowired
|
|
|
- private RedisClient redisClient;
|
|
|
-
|
|
|
- /**
|
|
|
- * 定时将“考生预约记录队列”中的数据保存至数据库
|
|
|
- * 注:每N秒执行一次
|
|
|
- */
|
|
|
- @Scheduled(fixedDelay = 10000, initialDelay = 30000)
|
|
|
- public void saveStudentApplyRecordJob() {
|
|
|
- long start = System.currentTimeMillis();
|
|
|
-
|
|
|
- RLock curLock = (RLock) concurrentService.getLock(CacheConstants.LOCK_STUDENT_APPLY_RECORD);
|
|
|
- try {
|
|
|
- if (!curLock.tryLock()) {
|
|
|
- log.info("[JOB] locking...");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- RQueue<ApplyRecordCacheBean> queue = redisClient.getRedissonClient()
|
|
|
- .getQueue(CacheConstants.QUEUE_STUDENT_APPLY_RECORD);
|
|
|
-
|
|
|
- int queueSize = queue.size();
|
|
|
- log.info("[JOB] queue size:{}", queueSize);
|
|
|
-
|
|
|
- for (int i = 1; i <= queueSize; i++) {
|
|
|
- ApplyRecordCacheBean value = queue.poll();
|
|
|
- if (value == null) {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- try {
|
|
|
- this.saveOrUpdate(value, i);
|
|
|
- } catch (Exception e) {
|
|
|
- // 保存至数据库失败,放回队列重试执行
|
|
|
- boolean success = queue.offer(value);
|
|
|
- log.error("[JOB] offerQueue:{} studentId:{} err:{}", success, value.getStudentId(), e.getMessage());
|
|
|
- }
|
|
|
- }
|
|
|
- } catch (Exception e) {
|
|
|
- log.error("[JOB] err:{}", e.getMessage(), e);
|
|
|
- } finally {
|
|
|
- try {
|
|
|
- // 解锁前检查当前线程是否持有该锁
|
|
|
- if (curLock.isLocked() && curLock.isHeldByCurrentThread()) {
|
|
|
- curLock.unlock();
|
|
|
- }
|
|
|
- } catch (Exception e) {
|
|
|
- // ignore
|
|
|
- }
|
|
|
-
|
|
|
- long end = System.currentTimeMillis();
|
|
|
- log.info("[JOB] cost:{}ms", end - start);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public void saveOrUpdate(ApplyRecordCacheBean queueBean, int index) {
|
|
|
- // 采用最新预约缓存记录进行数据库持久化,防止消费队列消息顺序异常
|
|
|
- ApplyRecordCacheBean cacheBean = applyTaskCacheService.getStudentApplyRecord(
|
|
|
- queueBean.getStudentId(), queueBean.getExamSiteId(), queueBean.getTimePeriodId());
|
|
|
- if (cacheBean == null) {
|
|
|
- log.warn("预约记录队列对应的缓存记录不存在!studentId:{} examSiteId:{} timePeriodId:{}",
|
|
|
- queueBean.getStudentId(), queueBean.getExamSiteId(), queueBean.getTimePeriodId());
|
|
|
-
|
|
|
- // 若缓存丢失,则采用队列数据补偿数据库持久化
|
|
|
- cacheBean = queueBean;
|
|
|
- }
|
|
|
-
|
|
|
- LambdaQueryWrapper<StudentApplyEntity> wrapper = new LambdaQueryWrapper<>();
|
|
|
- wrapper.eq(StudentApplyEntity::getExamSiteId, cacheBean.getExamSiteId());
|
|
|
- wrapper.eq(StudentApplyEntity::getTimePeriodId, cacheBean.getTimePeriodId());
|
|
|
- wrapper.eq(StudentApplyEntity::getStudentId, cacheBean.getStudentId());
|
|
|
- StudentApplyEntity data = studentApplyService.getOne(wrapper);
|
|
|
-
|
|
|
- String msg = String.format("%s_%s_%s_%s", cacheBean.getStudentId(), cacheBean.getExamSiteId(),
|
|
|
- cacheBean.getTimePeriodId(), cacheBean.getCancel());
|
|
|
- if (data != null) {
|
|
|
- // 存在预约记录,则修改
|
|
|
- data.setCancel(cacheBean.getCancel());
|
|
|
- data.setOperateId(cacheBean.getOperateId());
|
|
|
- data.setUpdateTime(cacheBean.getOperateTime());
|
|
|
-
|
|
|
- LambdaUpdateWrapper<StudentApplyEntity> updateWrapper = new LambdaUpdateWrapper<>();
|
|
|
- updateWrapper.set(StudentApplyEntity::getCancel, cacheBean.getCancel());
|
|
|
- updateWrapper.set(StudentApplyEntity::getOperateId, cacheBean.getOperateId());
|
|
|
- updateWrapper.set(StudentApplyEntity::getUpdateTime, cacheBean.getOperateTime());
|
|
|
- updateWrapper.eq(StudentApplyEntity::getId, data.getId());
|
|
|
- studentApplyService.update(updateWrapper);
|
|
|
- log.info("{} 预约修改!{}", msg, index);
|
|
|
- } else {
|
|
|
- // 不存在预约记录,则新增
|
|
|
- data = new StudentApplyEntity();
|
|
|
- data.setStudentId(cacheBean.getStudentId());
|
|
|
- data.setExamSiteId(cacheBean.getExamSiteId());
|
|
|
- data.setTimePeriodId(cacheBean.getTimePeriodId());
|
|
|
- data.setCancel(cacheBean.getCancel());
|
|
|
- data.setOperateId(cacheBean.getOperateId());
|
|
|
- data.setCreateTime(cacheBean.getOperateTime());
|
|
|
- data.setUpdateTime(cacheBean.getOperateTime());
|
|
|
- studentApplyService.save(data);
|
|
|
- log.info("{} 预约新增!{}", msg, index);
|
|
|
- }
|
|
|
-
|
|
|
- if (data.getCancel()) {
|
|
|
- // 保存“取消预约”操作记录
|
|
|
- operateLogService.insertOperateLog(cacheBean.getOperateId(), EventType.CANCEL_APPLY, JsonHelper.toJson(data));
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-}
|