Prechádzať zdrojové kódy

feat: 【IoT 物联网】实现场景规则定时触发器的注册,新增定时触发器处理器,支持场景规则的定时任务注册、更新、删除等生命周期管理

puhui999 9 mesiacov pred
rodič
commit
1cdae71d94

+ 24 - 4
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<IotSceneRuleAction> 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);
     }

+ 178 - 0
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 场景规则定时触发器处理器
+ * <p>
+ * 负责管理定时触发器的注册、更新、删除等操作
+ *
+ * @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<IotSceneRuleDO.Trigger> 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;
+    }
+}