fix: 开关定时任务,bug修复。
This commit is contained in:
@@ -2,6 +2,7 @@ package com.intc.iot.service.impl;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.intc.common.redis.utils.RedisUtils;
|
import com.intc.common.redis.utils.RedisUtils;
|
||||||
|
import com.intc.common.tenant.helper.TenantHelper;
|
||||||
import com.intc.fishery.constant.DefineDeviceWarnCode;
|
import com.intc.fishery.constant.DefineDeviceWarnCode;
|
||||||
import com.intc.fishery.domain.Device;
|
import com.intc.fishery.domain.Device;
|
||||||
import com.intc.fishery.domain.DeviceSwitch;
|
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 String DAILY_EXEC_LOCK_PREFIX = "fishery:timingCtrl:daily:exec:";
|
||||||
private static final DateTimeFormatter DATE_KEY_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
|
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 DeviceMapper deviceMapper;
|
||||||
private final DeviceSwitchMapper deviceSwitchMapper;
|
private final DeviceSwitchMapper deviceSwitchMapper;
|
||||||
@@ -141,22 +151,41 @@ public class TimingCtrlExecuteServiceImpl implements TimingCtrlExecuteService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int scanAndExecuteDailyTimingCtrl() {
|
public int scanAndExecuteDailyTimingCtrl() {
|
||||||
|
// 后台定时任务没有租户上下文,必须忽略租户过滤,否则SQL会拼接 WHERE tenant_id = NULL 导致查不到数据
|
||||||
|
return TenantHelper.ignore(() -> doScanAndExecuteDailyTimingCtrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
private int doScanAndExecuteDailyTimingCtrl() {
|
||||||
List<TimingCtrl> list = listEnabledDailyTimingCtrls();
|
List<TimingCtrl> list = listEnabledDailyTimingCtrls();
|
||||||
if (list.isEmpty()) {
|
if (list.isEmpty()) {
|
||||||
|
log.info("[TimingCtrl] 数据库中没有启用的每天循环定时控制记录(isOpen=1, loopType=1)");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalDateTime now = LocalDateTime.now();
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
log.info("[TimingCtrl] 扫描开始,当前时间={},查到 {} 条启用的定时控制", now, list.size());
|
||||||
int executedCount = 0;
|
int executedCount = 0;
|
||||||
for (TimingCtrl timingCtrl : list) {
|
for (TimingCtrl timingCtrl : list) {
|
||||||
try {
|
try {
|
||||||
if (timingCtrl.getSwitchId() == null || timingCtrl.getOpenTime() == null || timingCtrl.getCloseTime() == null) {
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalTime openTime = toLocalTime(timingCtrl.getOpenTime());
|
LocalTime openTime = toLocalTime(timingCtrl.getOpenTime());
|
||||||
LocalTime closeTime = toLocalTime(timingCtrl.getCloseTime());
|
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")) {
|
if (tryLock(timingCtrl.getId(), now.toLocalDate(), "open")) {
|
||||||
SwitchTurnResult result = executeSwitch(timingCtrl.getSwitchId(), 1,
|
SwitchTurnResult result = executeSwitch(timingCtrl.getSwitchId(), 1,
|
||||||
"定时控制管理", "定时任务到达开启时间", true);
|
"定时控制管理", "定时任务到达开启时间", true);
|
||||||
@@ -165,10 +194,12 @@ public class TimingCtrlExecuteServiceImpl implements TimingCtrlExecuteService {
|
|||||||
} else {
|
} else {
|
||||||
log.warn("[TimingCtrl] 开启执行失败,timingCtrlId={}, msg={}", timingCtrl.getId(), result.getMessage());
|
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")) {
|
if (tryLock(timingCtrl.getId(), now.toLocalDate(), "close")) {
|
||||||
SwitchTurnResult result = executeSwitch(timingCtrl.getSwitchId(), 0,
|
SwitchTurnResult result = executeSwitch(timingCtrl.getSwitchId(), 0,
|
||||||
"定时控制管理", "定时任务到达关闭时间", true);
|
"定时控制管理", "定时任务到达关闭时间", true);
|
||||||
@@ -177,6 +208,8 @@ public class TimingCtrlExecuteServiceImpl implements TimingCtrlExecuteService {
|
|||||||
} else {
|
} else {
|
||||||
log.warn("[TimingCtrl] 关闭执行失败,timingCtrlId={}, msg={}", timingCtrl.getId(), result.getMessage());
|
log.warn("[TimingCtrl] 关闭执行失败,timingCtrlId={}, msg={}", timingCtrl.getId(), result.getMessage());
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
log.debug("[TimingCtrl] 关闭: 今天已执行过,跳过,id={}", timingCtrl.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -192,7 +225,7 @@ public class TimingCtrlExecuteServiceImpl implements TimingCtrlExecuteService {
|
|||||||
return timingCtrlMapper.selectList(
|
return timingCtrlMapper.selectList(
|
||||||
new LambdaQueryWrapper<TimingCtrl>()
|
new LambdaQueryWrapper<TimingCtrl>()
|
||||||
.eq(TimingCtrl::getIsOpen, 1L)
|
.eq(TimingCtrl::getIsOpen, 1L)
|
||||||
.eq(TimingCtrl::getLoopType, 1L)
|
.eq(TimingCtrl::getLoopType, 2L)
|
||||||
.select(TimingCtrl::getId, TimingCtrl::getSwitchId, TimingCtrl::getOpenTime,
|
.select(TimingCtrl::getId, TimingCtrl::getSwitchId, TimingCtrl::getOpenTime,
|
||||||
TimingCtrl::getCloseTime, TimingCtrl::getLoopType, TimingCtrl::getIsOpen)
|
TimingCtrl::getCloseTime, TimingCtrl::getLoopType, TimingCtrl::getIsOpen)
|
||||||
);
|
);
|
||||||
@@ -213,6 +246,10 @@ public class TimingCtrlExecuteServiceImpl implements TimingCtrlExecuteService {
|
|||||||
|
|
||||||
private boolean tryLock(Long timingCtrlId, LocalDate date, String action) {
|
private boolean tryLock(Long timingCtrlId, LocalDate date, String action) {
|
||||||
String redisKey = DAILY_EXEC_LOCK_PREFIX + timingCtrlId + ":" + date.format(DATE_KEY_FORMATTER) + ":" + 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,19 +17,20 @@ import org.springframework.stereotype.Component;
|
|||||||
public class TimingCtrlExecuteTask {
|
public class TimingCtrlExecuteTask {
|
||||||
|
|
||||||
private static final long SCAN_DELAY_MS = 300000L;
|
private static final long SCAN_DELAY_MS = 300000L;
|
||||||
|
private static final long INITIAL_DELAY_MS = 10000L;
|
||||||
|
|
||||||
private final TimingCtrlExecuteService timingCtrlExecuteService;
|
private final TimingCtrlExecuteService timingCtrlExecuteService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 每5分钟扫描一次启用中的每天循环定时控制
|
* 每5分钟扫描一次启用中的每天循环定时控制
|
||||||
|
* 启动后10秒执行第一次扫描
|
||||||
*/
|
*/
|
||||||
@Scheduled(fixedDelay = SCAN_DELAY_MS)
|
@Scheduled(fixedDelay = SCAN_DELAY_MS, initialDelay = INITIAL_DELAY_MS)
|
||||||
public void scanDailyTimingCtrl() {
|
public void scanDailyTimingCtrl() {
|
||||||
try {
|
try {
|
||||||
|
log.info("[TimingCtrlTask] 开始扫描定时控制...");
|
||||||
int count = timingCtrlExecuteService.scanAndExecuteDailyTimingCtrl();
|
int count = timingCtrlExecuteService.scanAndExecuteDailyTimingCtrl();
|
||||||
if (count > 0) {
|
log.info("[TimingCtrlTask] 本次扫描完成,执行了 {} 条定时控制", count);
|
||||||
log.info("[TimingCtrlTask] 本次扫描执行了 {} 条定时控制", count);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("[TimingCtrlTask] 扫描定时控制失败: {}", e.getMessage(), e);
|
log.error("[TimingCtrlTask] 扫描定时控制失败: {}", e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user