Commit 1cdae71d9484d6827d1e06432e5d98d1e92258a7
1 parent
bc0292eb
feat: 【IoT 物联网】实现场景规则定时触发器的注册,新增定时触发器处理器,支持场景规则的定时任务注册、更新、删除等生命周期管理
Showing
2 changed files
with
202 additions
and
4 deletions
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; | @@ -17,11 +17,11 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; | ||
| 17 | import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; | 17 | import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; |
| 18 | import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotSceneRuleMapper; | 18 | import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotSceneRuleMapper; |
| 19 | import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum; | 19 | import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum; |
| 20 | -import cn.iocoder.yudao.module.iot.framework.job.core.IotSchedulerManager; | ||
| 21 | import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; | 20 | import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; |
| 22 | import cn.iocoder.yudao.module.iot.service.product.IotProductService; | 21 | import cn.iocoder.yudao.module.iot.service.product.IotProductService; |
| 23 | import cn.iocoder.yudao.module.iot.service.rule.scene.action.IotSceneRuleAction; | 22 | import cn.iocoder.yudao.module.iot.service.rule.scene.action.IotSceneRuleAction; |
| 24 | import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.IotSceneRuleMatcherManager; | 23 | import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.IotSceneRuleMatcherManager; |
| 24 | +import cn.iocoder.yudao.module.iot.service.rule.scene.timer.IotSceneRuleTimerHandler; | ||
| 25 | import jakarta.annotation.Resource; | 25 | import jakarta.annotation.Resource; |
| 26 | import lombok.extern.slf4j.Slf4j; | 26 | import lombok.extern.slf4j.Slf4j; |
| 27 | import org.springframework.stereotype.Service; | 27 | import org.springframework.stereotype.Service; |
| @@ -47,9 +47,6 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService { | @@ -47,9 +47,6 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService { | ||
| 47 | @Resource | 47 | @Resource |
| 48 | private IotSceneRuleMapper sceneRuleMapper; | 48 | private IotSceneRuleMapper sceneRuleMapper; |
| 49 | 49 | ||
| 50 | - // TODO @puhui999:定时任务,基于它调度; | ||
| 51 | - @Resource(name = "iotSchedulerManager") | ||
| 52 | - private IotSchedulerManager schedulerManager; | ||
| 53 | @Resource | 50 | @Resource |
| 54 | private IotProductService productService; | 51 | private IotProductService productService; |
| 55 | @Resource | 52 | @Resource |
| @@ -59,11 +56,17 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService { | @@ -59,11 +56,17 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService { | ||
| 59 | private IotSceneRuleMatcherManager sceneRuleMatcherManager; | 56 | private IotSceneRuleMatcherManager sceneRuleMatcherManager; |
| 60 | @Resource | 57 | @Resource |
| 61 | private List<IotSceneRuleAction> sceneRuleActions; | 58 | private List<IotSceneRuleAction> sceneRuleActions; |
| 59 | + @Resource | ||
| 60 | + private IotSceneRuleTimerHandler timerHandler; | ||
| 62 | 61 | ||
| 63 | @Override | 62 | @Override |
| 64 | public Long createSceneRule(IotSceneRuleSaveReqVO createReqVO) { | 63 | public Long createSceneRule(IotSceneRuleSaveReqVO createReqVO) { |
| 65 | IotSceneRuleDO sceneRule = BeanUtils.toBean(createReqVO, IotSceneRuleDO.class); | 64 | IotSceneRuleDO sceneRule = BeanUtils.toBean(createReqVO, IotSceneRuleDO.class); |
| 66 | sceneRuleMapper.insert(sceneRule); | 65 | sceneRuleMapper.insert(sceneRule); |
| 66 | + | ||
| 67 | + // 注册定时触发器 | ||
| 68 | + timerHandler.registerTimerTriggers(sceneRule); | ||
| 69 | + | ||
| 67 | return sceneRule.getId(); | 70 | return sceneRule.getId(); |
| 68 | } | 71 | } |
| 69 | 72 | ||
| @@ -74,6 +77,9 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService { | @@ -74,6 +77,9 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService { | ||
| 74 | // 更新 | 77 | // 更新 |
| 75 | IotSceneRuleDO updateObj = BeanUtils.toBean(updateReqVO, IotSceneRuleDO.class); | 78 | IotSceneRuleDO updateObj = BeanUtils.toBean(updateReqVO, IotSceneRuleDO.class); |
| 76 | sceneRuleMapper.updateById(updateObj); | 79 | sceneRuleMapper.updateById(updateObj); |
| 80 | + | ||
| 81 | + // 更新定时触发器 | ||
| 82 | + timerHandler.updateTimerTriggers(updateObj); | ||
| 77 | } | 83 | } |
| 78 | 84 | ||
| 79 | @Override | 85 | @Override |
| @@ -83,12 +89,26 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService { | @@ -83,12 +89,26 @@ public class IotSceneRuleServiceImpl implements IotSceneRuleService { | ||
| 83 | // 更新状态 | 89 | // 更新状态 |
| 84 | IotSceneRuleDO updateObj = new IotSceneRuleDO().setId(id).setStatus(status); | 90 | IotSceneRuleDO updateObj = new IotSceneRuleDO().setId(id).setStatus(status); |
| 85 | sceneRuleMapper.updateById(updateObj); | 91 | sceneRuleMapper.updateById(updateObj); |
| 92 | + | ||
| 93 | + // 根据状态管理定时触发器 | ||
| 94 | + if (CommonStatusEnum.isEnable(status)) { | ||
| 95 | + // 启用时,获取完整的场景规则信息并注册定时触发器 | ||
| 96 | + IotSceneRuleDO sceneRule = sceneRuleMapper.selectById(id); | ||
| 97 | + if (sceneRule != null) { | ||
| 98 | + timerHandler.registerTimerTriggers(sceneRule); | ||
| 99 | + } | ||
| 100 | + } else { | ||
| 101 | + // 禁用时,暂停定时触发器 | ||
| 102 | + timerHandler.pauseTimerTriggers(id); | ||
| 103 | + } | ||
| 86 | } | 104 | } |
| 87 | 105 | ||
| 88 | @Override | 106 | @Override |
| 89 | public void deleteSceneRule(Long id) { | 107 | public void deleteSceneRule(Long id) { |
| 90 | // 校验存在 | 108 | // 校验存在 |
| 91 | validateSceneRuleExists(id); | 109 | validateSceneRuleExists(id); |
| 110 | + // 删除定时触发器 | ||
| 111 | + timerHandler.unregisterTimerTriggers(id); | ||
| 92 | // 删除 | 112 | // 删除 |
| 93 | sceneRuleMapper.deleteById(id); | 113 | sceneRuleMapper.deleteById(id); |
| 94 | } | 114 | } |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/timer/IotSceneRuleTimerHandler.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.service.rule.scene.timer; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 4 | +import cn.hutool.core.util.ObjUtil; | ||
| 5 | +import cn.hutool.core.util.StrUtil; | ||
| 6 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||
| 7 | +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; | ||
| 8 | +import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum; | ||
| 9 | +import cn.iocoder.yudao.module.iot.framework.job.core.IotSchedulerManager; | ||
| 10 | +import cn.iocoder.yudao.module.iot.job.rule.IotSceneRuleJob; | ||
| 11 | +import jakarta.annotation.Resource; | ||
| 12 | +import lombok.extern.slf4j.Slf4j; | ||
| 13 | +import org.quartz.SchedulerException; | ||
| 14 | +import org.springframework.stereotype.Component; | ||
| 15 | + | ||
| 16 | +import java.util.List; | ||
| 17 | + | ||
| 18 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; | ||
| 19 | + | ||
| 20 | +/** | ||
| 21 | + * IoT 场景规则定时触发器处理器 | ||
| 22 | + * <p> | ||
| 23 | + * 负责管理定时触发器的注册、更新、删除等操作 | ||
| 24 | + * | ||
| 25 | + * @author HUIHUI | ||
| 26 | + */ | ||
| 27 | +@Component | ||
| 28 | +@Slf4j | ||
| 29 | +public class IotSceneRuleTimerHandler { | ||
| 30 | + | ||
| 31 | + @Resource(name = "iotSchedulerManager") | ||
| 32 | + private IotSchedulerManager schedulerManager; | ||
| 33 | + | ||
| 34 | + /** | ||
| 35 | + * 注册场景规则的定时触发器 | ||
| 36 | + * | ||
| 37 | + * @param sceneRule 场景规则 | ||
| 38 | + */ | ||
| 39 | + public void registerTimerTriggers(IotSceneRuleDO sceneRule) { | ||
| 40 | + if (sceneRule == null || CollUtil.isEmpty(sceneRule.getTriggers())) { | ||
| 41 | + return; | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + // 过滤出定时触发器 | ||
| 45 | + List<IotSceneRuleDO.Trigger> timerTriggers = filterList(sceneRule.getTriggers(), | ||
| 46 | + trigger -> ObjUtil.equals(trigger.getType(), IotSceneRuleTriggerTypeEnum.TIMER.getType())); | ||
| 47 | + | ||
| 48 | + if (CollUtil.isEmpty(timerTriggers)) { | ||
| 49 | + return; | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + // 注册每个定时触发器 | ||
| 53 | + timerTriggers.forEach(trigger -> registerSingleTimerTrigger(sceneRule, trigger)); | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + /** | ||
| 57 | + * 更新场景规则的定时触发器 | ||
| 58 | + * | ||
| 59 | + * @param sceneRule 场景规则 | ||
| 60 | + */ | ||
| 61 | + public void updateTimerTriggers(IotSceneRuleDO sceneRule) { | ||
| 62 | + if (sceneRule == null) { | ||
| 63 | + return; | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + // 先删除旧的定时任务 | ||
| 67 | + unregisterTimerTriggers(sceneRule.getId()); | ||
| 68 | + | ||
| 69 | + // 如果场景规则已禁用,则不重新注册 | ||
| 70 | + if (CommonStatusEnum.isDisable(sceneRule.getStatus())) { | ||
| 71 | + log.info("[updateTimerTriggers][场景规则({}) 已禁用,不注册定时触发器]", sceneRule.getId()); | ||
| 72 | + return; | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + // 重新注册定时触发器 | ||
| 76 | + registerTimerTriggers(sceneRule); | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + /** | ||
| 80 | + * 注销场景规则的定时触发器 | ||
| 81 | + * | ||
| 82 | + * @param sceneRuleId 场景规则ID | ||
| 83 | + */ | ||
| 84 | + public void unregisterTimerTriggers(Long sceneRuleId) { | ||
| 85 | + if (sceneRuleId == null) { | ||
| 86 | + return; | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + String jobName = buildJobName(sceneRuleId); | ||
| 90 | + try { | ||
| 91 | + schedulerManager.deleteJob(jobName); | ||
| 92 | + log.info("[unregisterTimerTriggers][场景规则({}) 定时触发器注销成功]", sceneRuleId); | ||
| 93 | + } catch (SchedulerException e) { | ||
| 94 | + log.error("[unregisterTimerTriggers][场景规则({}) 定时触发器注销失败]", sceneRuleId, e); | ||
| 95 | + } | ||
| 96 | + } | ||
| 97 | + | ||
| 98 | + /** | ||
| 99 | + * 暂停场景规则的定时触发器 | ||
| 100 | + * | ||
| 101 | + * @param sceneRuleId 场景规则ID | ||
| 102 | + */ | ||
| 103 | + public void pauseTimerTriggers(Long sceneRuleId) { | ||
| 104 | + if (sceneRuleId == null) { | ||
| 105 | + return; | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + String jobName = buildJobName(sceneRuleId); | ||
| 109 | + try { | ||
| 110 | + schedulerManager.pauseJob(jobName); | ||
| 111 | + log.info("[pauseTimerTriggers][场景规则({}) 定时触发器暂停成功]", sceneRuleId); | ||
| 112 | + } catch (SchedulerException e) { | ||
| 113 | + log.error("[pauseTimerTriggers][场景规则({}) 定时触发器暂停失败]", sceneRuleId, e); | ||
| 114 | + } | ||
| 115 | + } | ||
| 116 | + | ||
| 117 | + /** | ||
| 118 | + * 恢复场景规则的定时触发器 | ||
| 119 | + * | ||
| 120 | + * @param sceneRuleId 场景规则ID | ||
| 121 | + */ | ||
| 122 | + public void resumeTimerTriggers(Long sceneRuleId) { | ||
| 123 | + if (sceneRuleId == null) { | ||
| 124 | + return; | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + String jobName = buildJobName(sceneRuleId); | ||
| 128 | + try { | ||
| 129 | + schedulerManager.resumeJob(jobName); | ||
| 130 | + log.info("[resumeTimerTriggers][场景规则({}) 定时触发器恢复成功]", sceneRuleId); | ||
| 131 | + } catch (SchedulerException e) { | ||
| 132 | + log.error("[resumeTimerTriggers][场景规则({}) 定时触发器恢复失败]", sceneRuleId, e); | ||
| 133 | + } | ||
| 134 | + } | ||
| 135 | + | ||
| 136 | + /** | ||
| 137 | + * 注册单个定时触发器 | ||
| 138 | + * | ||
| 139 | + * @param sceneRule 场景规则 | ||
| 140 | + * @param trigger 定时触发器配置 | ||
| 141 | + */ | ||
| 142 | + private void registerSingleTimerTrigger(IotSceneRuleDO sceneRule, IotSceneRuleDO.Trigger trigger) { | ||
| 143 | + // 1. 参数校验 | ||
| 144 | + if (StrUtil.isBlank(trigger.getCronExpression())) { | ||
| 145 | + log.error("[registerSingleTimerTrigger][场景规则({}) 定时触发器缺少 CRON 表达式]", sceneRule.getId()); | ||
| 146 | + return; | ||
| 147 | + } | ||
| 148 | + | ||
| 149 | + // 2. 构建任务名称和数据 | ||
| 150 | + String jobName = buildJobName(sceneRule.getId()); | ||
| 151 | + | ||
| 152 | + try { | ||
| 153 | + // 3. 注册定时任务 | ||
| 154 | + schedulerManager.addOrUpdateJob( | ||
| 155 | + IotSceneRuleJob.class, | ||
| 156 | + jobName, | ||
| 157 | + trigger.getCronExpression(), | ||
| 158 | + IotSceneRuleJob.buildJobDataMap(sceneRule.getId()) | ||
| 159 | + ); | ||
| 160 | + | ||
| 161 | + log.info("[registerSingleTimerTrigger][场景规则({}) 定时触发器注册成功,CRON: {}]", | ||
| 162 | + sceneRule.getId(), trigger.getCronExpression()); | ||
| 163 | + } catch (SchedulerException e) { | ||
| 164 | + log.error("[registerSingleTimerTrigger][场景规则({}) 定时触发器注册失败,CRON: {}]", | ||
| 165 | + sceneRule.getId(), trigger.getCronExpression(), e); | ||
| 166 | + } | ||
| 167 | + } | ||
| 168 | + | ||
| 169 | + /** | ||
| 170 | + * 构建任务名称 | ||
| 171 | + * | ||
| 172 | + * @param sceneRuleId 场景规则ID | ||
| 173 | + * @return 任务名称 | ||
| 174 | + */ | ||
| 175 | + private String buildJobName(Long sceneRuleId) { | ||
| 176 | + return "iot_scene_rule_timer_" + sceneRuleId; | ||
| 177 | + } | ||
| 178 | +} |