Commit 1cdae71d9484d6827d1e06432e5d98d1e92258a7

Authored by puhui999
1 parent bc0292eb

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

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 +}