fix: 开关定时任务,bug修复。

This commit is contained in:
tianyongbao
2026-07-01 11:35:03 +08:00
parent 7ae7c42f34
commit b7a1f761c3
2 changed files with 47 additions and 9 deletions

View File

@@ -2,6 +2,7 @@ package com.intc.iot.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.intc.common.redis.utils.RedisUtils;
import com.intc.common.tenant.helper.TenantHelper;
import com.intc.fishery.constant.DefineDeviceWarnCode;
import com.intc.fishery.domain.Device;
import com.intc.fishery.domain.DeviceSwitch;
@@ -40,7 +41,16 @@ public class TimingCtrlExecuteServiceImpl implements TimingCtrlExecuteService {
private static final String DAILY_EXEC_LOCK_PREFIX = "fishery:timingCtrl:daily:exec:";
private static final DateTimeFormatter DATE_KEY_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
private static final long SCAN_WINDOW_MINUTES = 5L;
private static final long SCAN_WINDOW_MINUTES = 10L;
/**
* 启动时打印日志,用于确认 Bean 是否成功创建
*/
@jakarta.annotation.PostConstruct
public void init() {
log.info("[TimingCtrl] TimingCtrlExecuteService 已初始化,扫描窗口={}分钟Redis锁前缀={}",
SCAN_WINDOW_MINUTES, DAILY_EXEC_LOCK_PREFIX);
}
private final DeviceMapper deviceMapper;
private final DeviceSwitchMapper deviceSwitchMapper;
@@ -141,22 +151,41 @@ public class TimingCtrlExecuteServiceImpl implements TimingCtrlExecuteService {
@Override
public int scanAndExecuteDailyTimingCtrl() {
// 后台定时任务没有租户上下文必须忽略租户过滤否则SQL会拼接 WHERE tenant_id = NULL 导致查不到数据
return TenantHelper.ignore(() -> doScanAndExecuteDailyTimingCtrl());
}
private int doScanAndExecuteDailyTimingCtrl() {
List<TimingCtrl> list = listEnabledDailyTimingCtrls();
if (list.isEmpty()) {
log.info("[TimingCtrl] 数据库中没有启用的每天循环定时控制记录(isOpen=1, loopType=1)");
return 0;
}
LocalDateTime now = LocalDateTime.now();
log.info("[TimingCtrl] 扫描开始,当前时间={},查到 {} 条启用的定时控制", now, list.size());
int executedCount = 0;
for (TimingCtrl timingCtrl : list) {
try {
if (timingCtrl.getSwitchId() == null || timingCtrl.getOpenTime() == null || timingCtrl.getCloseTime() == null) {
log.debug("[TimingCtrl] 跳过: 字段为空id={}, switchId={}, openTime={}, closeTime={}",
timingCtrl.getId(), timingCtrl.getSwitchId(), timingCtrl.getOpenTime(), timingCtrl.getCloseTime());
continue;
}
LocalTime openTime = toLocalTime(timingCtrl.getOpenTime());
LocalTime closeTime = toLocalTime(timingCtrl.getCloseTime());
if (isDueInLookbackWindow(now, openTime)) {
boolean openDue = isDueInLookbackWindow(now, openTime);
boolean closeDue = isDueInLookbackWindow(now, closeTime);
if (!openDue && !closeDue) {
log.debug("[TimingCtrl] 跳过: 未到执行时间id={}, openTime={}, closeTime={}, now={}",
timingCtrl.getId(), openTime, closeTime, now.toLocalTime());
continue;
}
if (openDue) {
if (tryLock(timingCtrl.getId(), now.toLocalDate(), "open")) {
SwitchTurnResult result = executeSwitch(timingCtrl.getSwitchId(), 1,
"定时控制管理", "定时任务到达开启时间", true);
@@ -165,10 +194,12 @@ public class TimingCtrlExecuteServiceImpl implements TimingCtrlExecuteService {
} else {
log.warn("[TimingCtrl] 开启执行失败timingCtrlId={}, msg={}", timingCtrl.getId(), result.getMessage());
}
} else {
log.debug("[TimingCtrl] 开启: 今天已执行过跳过id={}", timingCtrl.getId());
}
}
if (isDueInLookbackWindow(now, closeTime)) {
if (closeDue) {
if (tryLock(timingCtrl.getId(), now.toLocalDate(), "close")) {
SwitchTurnResult result = executeSwitch(timingCtrl.getSwitchId(), 0,
"定时控制管理", "定时任务到达关闭时间", true);
@@ -177,6 +208,8 @@ public class TimingCtrlExecuteServiceImpl implements TimingCtrlExecuteService {
} else {
log.warn("[TimingCtrl] 关闭执行失败timingCtrlId={}, msg={}", timingCtrl.getId(), result.getMessage());
}
} else {
log.debug("[TimingCtrl] 关闭: 今天已执行过跳过id={}", timingCtrl.getId());
}
}
} catch (Exception e) {
@@ -192,7 +225,7 @@ public class TimingCtrlExecuteServiceImpl implements TimingCtrlExecuteService {
return timingCtrlMapper.selectList(
new LambdaQueryWrapper<TimingCtrl>()
.eq(TimingCtrl::getIsOpen, 1L)
.eq(TimingCtrl::getLoopType, 1L)
.eq(TimingCtrl::getLoopType, 2L)
.select(TimingCtrl::getId, TimingCtrl::getSwitchId, TimingCtrl::getOpenTime,
TimingCtrl::getCloseTime, TimingCtrl::getLoopType, TimingCtrl::getIsOpen)
);
@@ -213,6 +246,10 @@ public class TimingCtrlExecuteServiceImpl implements TimingCtrlExecuteService {
private boolean tryLock(Long timingCtrlId, LocalDate date, String action) {
String redisKey = DAILY_EXEC_LOCK_PREFIX + timingCtrlId + ":" + date.format(DATE_KEY_FORMATTER) + ":" + action;
return RedisUtils.setObjectIfAbsent(redisKey, "1", Duration.ofMinutes(5));
boolean locked = RedisUtils.setObjectIfAbsent(redisKey, "1", Duration.ofHours(25));
if (locked) {
log.info("[TimingCtrl] 获取执行锁成功timingCtrlId={}, date={}, action={}", timingCtrlId, date, action);
}
return locked;
}
}

View File

@@ -17,19 +17,20 @@ import org.springframework.stereotype.Component;
public class TimingCtrlExecuteTask {
private static final long SCAN_DELAY_MS = 300000L;
private static final long INITIAL_DELAY_MS = 10000L;
private final TimingCtrlExecuteService timingCtrlExecuteService;
/**
* 每5分钟扫描一次启用中的每天循环定时控制
* 启动后10秒执行第一次扫描
*/
@Scheduled(fixedDelay = SCAN_DELAY_MS)
@Scheduled(fixedDelay = SCAN_DELAY_MS, initialDelay = INITIAL_DELAY_MS)
public void scanDailyTimingCtrl() {
try {
log.info("[TimingCtrlTask] 开始扫描定时控制...");
int count = timingCtrlExecuteService.scanAndExecuteDailyTimingCtrl();
if (count > 0) {
log.info("[TimingCtrlTask] 本次扫描执行了 {} 条定时控制", count);
}
log.info("[TimingCtrlTask] 本次扫描完成,执行了 {} 条定时控制", count);
} catch (Exception e) {
log.error("[TimingCtrlTask] 扫描定时控制失败: {}", e.getMessage(), e);
}