Jelajahi Sumber

开发规则引擎中执行冷却机制,上报触发规则后进入冷却期,在冷却期范围内不再触发规则

james 6 hari lalu
induk
melakukan
79ae95495f

+ 37 - 0
service-rule/service-rule-biz/src/main/java/com/usky/rule/cache/DeviceAcqTriggerCooldownCache.java

@@ -0,0 +1,37 @@
+package com.usky.rule.cache;
+
+import com.usky.common.redis.core.RedisHelper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 设备采集触发规则成功执行动作后的冷却窗口,避免短时间内频繁上报反复执行同一规则。
+ */
+@Component
+public class DeviceAcqTriggerCooldownCache {
+
+    private static final String KEY_PREFIX = "ruleEngine:deviceAcqCooldown:";
+
+    @Autowired
+    private RedisHelper redisHelper;
+
+    public boolean isInCooldown(Long ruleEngineId, String deviceId) {
+        return redisHelper.hasKey(buildKey(ruleEngineId, deviceId));
+    }
+
+    /**
+     * 执行成功后调用,在 {@code cooldownSeconds} 秒内同规则同设备不再触发动作。
+     */
+    public void startCooldown(Long ruleEngineId, String deviceId, long cooldownSeconds) {
+        if (cooldownSeconds <= 0) {
+            return;
+        }
+        redisHelper.set(buildKey(ruleEngineId, deviceId), "1", cooldownSeconds, TimeUnit.SECONDS);
+    }
+
+    private static String buildKey(Long ruleEngineId, String deviceId) {
+        return KEY_PREFIX + ruleEngineId + ":" + deviceId;
+    }
+}

+ 14 - 0
service-rule/service-rule-biz/src/main/java/com/usky/rule/subscribe/TriggerDeviceUtil.java

@@ -28,6 +28,7 @@ import com.usky.rule.vo.log.DeviceTriggerLog;
 import com.usky.rule.vo.log.RuleEngineDetailLog;
 import com.usky.rule.vo.trigger.DeviceTrigger;
 import com.usky.rule.vo.visualization.SimpleVO;
+import com.usky.rule.cache.DeviceAcqTriggerCooldownCache;
 import com.usky.rule.cache.DeviceTriggerIncludeMinuteCache;
 import com.usky.rule.util.RuleEngineCallBack;
 import com.usky.rule.util.RuleEngineUtil;
@@ -46,6 +47,7 @@ import com.usky.rule.vo.log.CronTriggerLog;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.expression.ExpressionParser;
 import org.springframework.expression.spel.standard.SpelExpressionParser;
 import org.springframework.stereotype.Component;
@@ -60,6 +62,11 @@ public class TriggerDeviceUtil {
     private RuleEngineDeviceMapper ruleEngineDeviceMapper;
     @Autowired
     private RemoteTsdbProxyService remoteTsdbProxyService;
+    @Autowired
+    private DeviceAcqTriggerCooldownCache deviceAcqTriggerCooldownCache;
+    /** 规则对同一设备成功执行动作后,在多少秒内忽略再次触发(0 表示不启用冷却)。 */
+    @Value("${rule.engine.device-acq-cooldown-seconds:300}")
+    private long deviceAcqCooldownSeconds;
     private static final Integer maxNumberOfReminders = 1;
     private static final ExpressionParser parser = new SpelExpressionParser();
 
@@ -102,6 +109,12 @@ public class TriggerDeviceUtil {
                                     Map<String, String> meetMinuteExpressionMap = new HashMap();
                                     boolean triggerAction = this.meetDeviceAcqTriggerAction(ruleEngineId, deviceId, currDataTime, valueMap, deviceTriggers, meetMinuteExpressionMap, meetTriggerConditionList);
                                     if (triggerAction) {
+                                        if (this.deviceAcqCooldownSeconds > 0
+                                                && this.deviceAcqTriggerCooldownCache.isInCooldown(ruleEngineId, deviceId)) {
+                                            log.debug("ruleEngineId={} deviceId={} skipped: within acq cooldown ({}s)",
+                                                    ruleEngineId, deviceId, this.deviceAcqCooldownSeconds);
+                                            return;
+                                        }
                                         log.info("triggerAction is true");
                                         this.setTriggerLog(now, ruleEngineDetailLog, deviceId, null, TriggerValueTypeEnum.ACQ.getValue(), TriggerTypeEnum.DEVICE, meetTriggerConditionList, valueMap);
                                         List<CronConstraint> cronConstraints = this.ruleEngineService.getCronConstraints(ruleEngineDetail.getConstraints());
@@ -112,6 +125,7 @@ public class TriggerDeviceUtil {
                                             log.info("ruleEngineId={} constraints satisfied, executing actions", ruleEngineId);
                                             this.ruleEngineUtil.performMultipleDevicesControl(ruleEngineId, true, TriggerTypeEnum.DEVICE.getType(), ruleEngine.getProjectId(), ruleEngine.getSpaceId(), actions, ruleEngineDetailLog);
                                             this.clearMeetConditionCache(ruleEngineId, deviceId, meetMinuteExpressionMap);
+                                            this.deviceAcqTriggerCooldownCache.startCooldown(ruleEngineId, deviceId, this.deviceAcqCooldownSeconds);
                                         } else if (!cronOk) {
                                             log.debug("ruleEngineId={} skipped: cron constraint not satisfied at {}", ruleEngineId, currDataTime);
                                         }