diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleServiceImpl.java index 7cbc5b56be..ee7351f717 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleServiceImpl.java @@ -17,11 +17,11 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotSceneRuleMapper; import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum; -import cn.iocoder.yudao.module.iot.framework.job.core.IotSchedulerManager; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; import cn.iocoder.yudao.module.iot.service.product.IotProductService; import cn.iocoder.yudao.module.iot.service.rule.scene.action.IotSceneRuleAction; import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.IotSceneRuleMatcherManager; +import cn.iocoder.yudao.module.iot.service.rule.scene.timer.IotSceneRuleTimerHandler; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -47,9 +47,6 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService { @Resource private IotSceneRuleMapper sceneRuleMapper; - // TODO @puhui999:定时任务,基于它调度; - @Resource(name = "iotSchedulerManager") - private IotSchedulerManager schedulerManager; @Resource private IotProductService productService; @Resource @@ -59,11 +56,17 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService { private IotSceneRuleMatcherManager sceneRuleMatcherManager; @Resource private List sceneRuleActions; + @Resource + private IotSceneRuleTimerHandler timerHandler; @Override public Long createSceneRule(IotSceneRuleSaveReqVO createReqVO) { IotSceneRuleDO sceneRule = BeanUtils.toBean(createReqVO, IotSceneRuleDO.class); sceneRuleMapper.insert(sceneRule); + + // 注册定时触发器 + timerHandler.registerTimerTriggers(sceneRule); + return sceneRule.getId(); } @@ -74,6 +77,9 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService { // 更新 IotSceneRuleDO updateObj = BeanUtils.toBean(updateReqVO, IotSceneRuleDO.class); sceneRuleMapper.updateById(updateObj); + + // 更新定时触发器 + timerHandler.updateTimerTriggers(updateObj); } @Override @@ -83,12 +89,26 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService { // 更新状态 IotSceneRuleDO updateObj = new IotSceneRuleDO().setId(id).setStatus(status); sceneRuleMapper.updateById(updateObj); + + // 根据状态管理定时触发器 + if (CommonStatusEnum.isEnable(status)) { + // 启用时,获取完整的场景规则信息并注册定时触发器 + IotSceneRuleDO sceneRule = sceneRuleMapper.selectById(id); + if (sceneRule != null) { + timerHandler.registerTimerTriggers(sceneRule); + } + } else { + // 禁用时,暂停定时触发器 + timerHandler.pauseTimerTriggers(id); + } } @Override public void deleteSceneRule(Long id) { // 校验存在 validateSceneRuleExists(id); + // 删除定时触发器 + timerHandler.unregisterTimerTriggers(id); // 删除 sceneRuleMapper.deleteById(id); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/timer/IotSceneRuleTimerHandler.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/timer/IotSceneRuleTimerHandler.java new file mode 100644 index 0000000000..ddb6367506 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/timer/IotSceneRuleTimerHandler.java @@ -0,0 +1,178 @@ +package cn.iocoder.yudao.module.iot.service.rule.scene.timer; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; +import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum; +import cn.iocoder.yudao.module.iot.framework.job.core.IotSchedulerManager; +import cn.iocoder.yudao.module.iot.job.rule.IotSceneRuleJob; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.quartz.SchedulerException; +import org.springframework.stereotype.Component; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; + +/** + * IoT 场景规则定时触发器处理器 + *

+ * 负责管理定时触发器的注册、更新、删除等操作 + * + * @author HUIHUI + */ +@Component +@Slf4j +public class IotSceneRuleTimerHandler { + + @Resource(name = "iotSchedulerManager") + private IotSchedulerManager schedulerManager; + + /** + * 注册场景规则的定时触发器 + * + * @param sceneRule 场景规则 + */ + public void registerTimerTriggers(IotSceneRuleDO sceneRule) { + if (sceneRule == null || CollUtil.isEmpty(sceneRule.getTriggers())) { + return; + } + + // 过滤出定时触发器 + List timerTriggers = filterList(sceneRule.getTriggers(), + trigger -> ObjUtil.equals(trigger.getType(), IotSceneRuleTriggerTypeEnum.TIMER.getType())); + + if (CollUtil.isEmpty(timerTriggers)) { + return; + } + + // 注册每个定时触发器 + timerTriggers.forEach(trigger -> registerSingleTimerTrigger(sceneRule, trigger)); + } + + /** + * 更新场景规则的定时触发器 + * + * @param sceneRule 场景规则 + */ + public void updateTimerTriggers(IotSceneRuleDO sceneRule) { + if (sceneRule == null) { + return; + } + + // 先删除旧的定时任务 + unregisterTimerTriggers(sceneRule.getId()); + + // 如果场景规则已禁用,则不重新注册 + if (CommonStatusEnum.isDisable(sceneRule.getStatus())) { + log.info("[updateTimerTriggers][场景规则({}) 已禁用,不注册定时触发器]", sceneRule.getId()); + return; + } + + // 重新注册定时触发器 + registerTimerTriggers(sceneRule); + } + + /** + * 注销场景规则的定时触发器 + * + * @param sceneRuleId 场景规则ID + */ + public void unregisterTimerTriggers(Long sceneRuleId) { + if (sceneRuleId == null) { + return; + } + + String jobName = buildJobName(sceneRuleId); + try { + schedulerManager.deleteJob(jobName); + log.info("[unregisterTimerTriggers][场景规则({}) 定时触发器注销成功]", sceneRuleId); + } catch (SchedulerException e) { + log.error("[unregisterTimerTriggers][场景规则({}) 定时触发器注销失败]", sceneRuleId, e); + } + } + + /** + * 暂停场景规则的定时触发器 + * + * @param sceneRuleId 场景规则ID + */ + public void pauseTimerTriggers(Long sceneRuleId) { + if (sceneRuleId == null) { + return; + } + + String jobName = buildJobName(sceneRuleId); + try { + schedulerManager.pauseJob(jobName); + log.info("[pauseTimerTriggers][场景规则({}) 定时触发器暂停成功]", sceneRuleId); + } catch (SchedulerException e) { + log.error("[pauseTimerTriggers][场景规则({}) 定时触发器暂停失败]", sceneRuleId, e); + } + } + + /** + * 恢复场景规则的定时触发器 + * + * @param sceneRuleId 场景规则ID + */ + public void resumeTimerTriggers(Long sceneRuleId) { + if (sceneRuleId == null) { + return; + } + + String jobName = buildJobName(sceneRuleId); + try { + schedulerManager.resumeJob(jobName); + log.info("[resumeTimerTriggers][场景规则({}) 定时触发器恢复成功]", sceneRuleId); + } catch (SchedulerException e) { + log.error("[resumeTimerTriggers][场景规则({}) 定时触发器恢复失败]", sceneRuleId, e); + } + } + + /** + * 注册单个定时触发器 + * + * @param sceneRule 场景规则 + * @param trigger 定时触发器配置 + */ + private void registerSingleTimerTrigger(IotSceneRuleDO sceneRule, IotSceneRuleDO.Trigger trigger) { + // 1. 参数校验 + if (StrUtil.isBlank(trigger.getCronExpression())) { + log.error("[registerSingleTimerTrigger][场景规则({}) 定时触发器缺少 CRON 表达式]", sceneRule.getId()); + return; + } + + // 2. 构建任务名称和数据 + String jobName = buildJobName(sceneRule.getId()); + + try { + // 3. 注册定时任务 + schedulerManager.addOrUpdateJob( + IotSceneRuleJob.class, + jobName, + trigger.getCronExpression(), + IotSceneRuleJob.buildJobDataMap(sceneRule.getId()) + ); + + log.info("[registerSingleTimerTrigger][场景规则({}) 定时触发器注册成功,CRON: {}]", + sceneRule.getId(), trigger.getCronExpression()); + } catch (SchedulerException e) { + log.error("[registerSingleTimerTrigger][场景规则({}) 定时触发器注册失败,CRON: {}]", + sceneRule.getId(), trigger.getCronExpression(), e); + } + } + + /** + * 构建任务名称 + * + * @param sceneRuleId 场景规则ID + * @return 任务名称 + */ + private String buildJobName(Long sceneRuleId) { + return "iot_scene_rule_timer_" + sceneRuleId; + } +}