From b7a1f761c3eae64955a32942e94df277c3d38f17 Mon Sep 17 00:00:00 2001 From: tianyongbao Date: Wed, 1 Jul 2026 11:35:03 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=BC=80=E5=85=B3=E5=AE=9A=E6=97=B6?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=EF=BC=8Cbug=E4=BF=AE=E5=A4=8D=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/TimingCtrlExecuteServiceImpl.java | 47 +++++++++++++++++-- .../intc/iot/task/TimingCtrlExecuteTask.java | 9 ++-- 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/intc-modules/intc-iot/src/main/java/com/intc/iot/service/impl/TimingCtrlExecuteServiceImpl.java b/intc-modules/intc-iot/src/main/java/com/intc/iot/service/impl/TimingCtrlExecuteServiceImpl.java index e297dd1..8158667 100644 --- a/intc-modules/intc-iot/src/main/java/com/intc/iot/service/impl/TimingCtrlExecuteServiceImpl.java +++ b/intc-modules/intc-iot/src/main/java/com/intc/iot/service/impl/TimingCtrlExecuteServiceImpl.java @@ -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 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() .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; } } diff --git a/intc-modules/intc-iot/src/main/java/com/intc/iot/task/TimingCtrlExecuteTask.java b/intc-modules/intc-iot/src/main/java/com/intc/iot/task/TimingCtrlExecuteTask.java index 45cd2c4..a935b56 100644 --- a/intc-modules/intc-iot/src/main/java/com/intc/iot/task/TimingCtrlExecuteTask.java +++ b/intc-modules/intc-iot/src/main/java/com/intc/iot/task/TimingCtrlExecuteTask.java @@ -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); }