Selaa lähdekoodia

修复报警无法正常恢复的bug

lixing 4 vuotta sitten
vanhempi
commit
851fcfccae

+ 5 - 1
.gitignore

@@ -32,4 +32,8 @@ build/
 
 ### rebel ###
 **/src/main/resources/rebel.xml
-**/src/main/resources/rebel-remote.xml
+**/src/main/resources/rebel-remote.xml
+
+### DS_Store
+**/src/main/.DS_Store
+**/src/main/resources/.DS_Store

+ 3 - 4
src/main/java/com/persagy/cache/AlarmInfoCache.java

@@ -152,20 +152,19 @@ public class AlarmInfoCache {
         try {
             Expression triggerCompiledExp = AviatorEvaluator.compile(trigger, true);
         } catch (Exception e) {
-            log.info("触发表达式:", trigger);
+            log.info("触发表达式:{}", trigger);
             log.error("触发表表达式不合法,请校验", e);
             throw new IllegalArgumentException("触发表表达式不合法", e);
         }
         try {
             Expression endCompiledExp = AviatorEvaluator.compile(end, true);
         } catch (Exception e) {
-            log.error("恢复表达式:", end);
+            log.error("恢复表达式:{}", end);
             log.error("恢复表达式不合法,请校验", e);
             throw new IllegalArgumentException("恢复表达式不合法", e);
         }
         alarmDefineMap.put(definitionId, alarmDefine);
-        for (int i = 0; i < infoCodes.size(); i++) {
-            JSONObject infoCode = infoCodes.get(i);
+        for (JSONObject infoCode : infoCodes) {
             String meterId = infoCode.getString("meterId");
             String funcId = infoCode.getString("funcId");
             putAlarmDefinitionIdByMeterFuncId(meterId, funcId, alarmDefine);

+ 99 - 0
src/main/java/com/persagy/cache/CreatedAlarmIdsCache.java

@@ -0,0 +1,99 @@
+package com.persagy.cache;
+
+
+import com.persagy.entity.AlarmRecordIdsCache;
+import com.persagy.repository.AlarmRecordIdsCacheRepository;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @description: 存放云端返回的报警id, 当报警恢复或过期后移除报警id
+ * @author: lixing
+ * @company: Persagy Technology Co.,Ltd
+ * @since: 2021/1/21 下午8:28
+ * @version: V1.0
+ */
+@Component
+@Slf4j
+public class CreatedAlarmIdsCache {
+    @Autowired
+    private AlarmRecordIdsCacheRepository alarmRecordIdsCacheRepository;
+    /**
+     * 报警id - 报警id
+     */
+    private Set<String> alarmIdSet;
+
+    /**
+     * @description: 初始化方法,查询数据库中的数据,放入set
+     * @param:
+     * @return:
+     * @exception:
+     * @author: lixing
+     * @company: Persagy Technology Co.,Ltd
+     * @since: 2021/1/21 下午8:43
+     * @version: V1.0
+     */
+    public void init() {
+        alarmIdSet = Collections.synchronizedSet(new HashSet<>());
+        Iterable<AlarmRecordIdsCache> alarmRecordIds = alarmRecordIdsCacheRepository.findAll();
+        alarmRecordIds.forEach(alarmRecordIdsCache -> alarmIdSet.add(alarmRecordIdsCache.getId()));
+        log.info("CreatedAlarmIdsCache初始化完成");
+        log.info("当前CreatedAlarmIdsCache缓存为:[{}]", alarmIdSet.toString());
+    }
+
+    /**
+     * @description: 将报警id放入缓存
+     * @param: alarmId
+     * @return: void
+     * @exception:
+     * @author: lixing
+     * @company: Persagy Technology Co.,Ltd
+     * @since: 2021/1/21 下午8:44
+     * @version: V1.0
+     */
+    public void put(String alarmId) {
+        // 存入缓存
+        alarmIdSet.add(alarmId);
+        // 持久化到数据库
+        AlarmRecordIdsCache alarmRecordIdsCache = new AlarmRecordIdsCache();
+        alarmRecordIdsCache.setId(alarmId);
+        alarmRecordIdsCacheRepository.save(alarmRecordIdsCache);
+        log.info("报警id[{}]放入CreatedAlarmIdsCache", alarmId);
+        log.info("当前CreatedAlarmIdsCache缓存为:[{}]", alarmIdSet.toString());
+    }
+
+    /**
+     * @description: 将报警id从缓存中移除
+     * @param: alarmId
+     * @return: void
+     * @exception:
+     * @author: lixing
+     * @company: Persagy Technology Co.,Ltd
+     * @since: 2021/1/21 下午8:44
+     * @version: V1.0
+     */
+    public void remove(String alarmId) {
+        // 从缓存中移除
+        alarmIdSet.remove(alarmId);
+        // 从数据库中移除
+        alarmRecordIdsCacheRepository.deleteById(alarmId);
+        log.info("报警id[{}]从CreatedAlarmIdsCache移除", alarmId);
+        log.info("当前CreatedAlarmIdsCache缓存为:[{}]", alarmIdSet.toString());
+    }
+
+    public boolean contains(String alarmId) {
+        return alarmIdSet.contains(alarmId);
+    }
+
+    //    public static void main(String[] args) {
+    //        HashSet<Integer> objects = new HashSet<>();
+    //        objects.add(1);
+    //        objects.add(2);
+    //        System.out.println(objects.toString());
+    //    }
+}

+ 14 - 6
src/main/java/com/persagy/client/GroupNettyClient.java

@@ -1,5 +1,6 @@
 package com.persagy.client;
 
+import com.persagy.cache.CreatedAlarmIdsCache;
 import com.persagy.job.NettyMessageQueue;
 import com.persagy.repository.AlarmRecordRepository;
 import com.persagy.service.AlarmDefineService;
@@ -36,6 +37,9 @@ public class GroupNettyClient {
     AlarmDefineService alarmDefineService;
     @Autowired
     AlarmRecordRepository alarmRecordRepository;
+    @Autowired
+    CreatedAlarmIdsCache createdAlarmIdsCache;
+
     static Bootstrap groupBootstrap = new Bootstrap();
     public static Channel channelGroup;
     @Value("${group.alarm.host:127.0.0.1}")
@@ -58,11 +62,11 @@ public class GroupNettyClient {
 
 
     /**
+     * @param
      * @description:启动netty客户端
      * @exception:
      * @author: LuoGuangyi
      * @company: Persagy Technology Co.,Ltd
-     * @param
      * @return: void
      * @since: 2020/10/20 15:54
      * @version: V1.0
@@ -85,7 +89,11 @@ public class GroupNettyClient {
                             ch.pipeline().addLast(new StringDecoder());
                             ch.pipeline().addLast(new StringEncoder());
                             // pipeline可以理解为所有handler的初始化容器
-                            ch.pipeline().addLast(new GroupNettyClientHandler(groupNettyClient, alarmDefineService,alarmRecordRepository));// 添加自定义handler
+                            ch.pipeline().addLast(new GroupNettyClientHandler(
+                                    groupNettyClient,
+                                    alarmDefineService,
+                                    alarmRecordRepository,
+                                    createdAlarmIdsCache));// 添加自定义handler
                         }
                     });
             // 连接远程节点,等待连接完成
@@ -139,11 +147,11 @@ public class GroupNettyClient {
         }
     }*/
     public void sendMessage(String msg) throws InterruptedException {
-        log.info("给云端发送数据:[{}]",msg);
-        if(channelGroup.isWritable()){
+        log.info("给云端发送数据:[{}]", msg);
+        if (channelGroup.isWritable()) {
             channelGroup.writeAndFlush(msg);
-        }else {
-            log.warn("云端netty不可写,放入缓冲队列中[{}]",msg);
+        } else {
+            log.warn("云端netty不可写,放入缓冲队列中[{}]", msg);
             NettyMessageQueue.getNettyMessageQueue().produce(msg);
         }
     }

+ 18 - 15
src/main/java/com/persagy/client/GroupNettyClientHandler.java

@@ -5,6 +5,7 @@ import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.date.TimeInterval;
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.TypeReference;
+import com.persagy.cache.CreatedAlarmIdsCache;
 import com.persagy.entity.AlarmDefine;
 import com.persagy.entity.NettyMessage;
 import com.persagy.entity.ZktAlarmRecordDO;
@@ -42,12 +43,18 @@ public class GroupNettyClientHandler extends ChannelInboundHandlerAdapter {
     private AlarmDefineService alarmDefineService;
     private GroupNettyClient groupNettyClient;
     private AlarmRecordRepository alarmRecordRepository;
+    private CreatedAlarmIdsCache createdAlarmIdsCache;
 
 
-    public GroupNettyClientHandler(GroupNettyClient groupNettyClient, AlarmDefineService alarmDefineService, AlarmRecordRepository alarmRecordRepository) {
+    public GroupNettyClientHandler(
+            GroupNettyClient groupNettyClient,
+            AlarmDefineService alarmDefineService,
+            AlarmRecordRepository alarmRecordRepository,
+            CreatedAlarmIdsCache createdAlarmIdsCache) {
         this.alarmDefineService = alarmDefineService;
         this.groupNettyClient = groupNettyClient;
         this.alarmRecordRepository = alarmRecordRepository;
+        this.createdAlarmIdsCache = createdAlarmIdsCache;
     }
 
     @Override
@@ -120,7 +127,6 @@ public class GroupNettyClientHandler extends ChannelInboundHandlerAdapter {
         }
     }
 
-    @Transactional
     public void handlerMsg(ChannelHandlerContext channelHandlerContext, Object msg) throws Exception {
         if (StringUtil.isJSONObject((String) msg)) {
             NettyMessage message = StringUtil.tranferItemToDTO((String) msg, NettyMessage.class);
@@ -144,33 +150,30 @@ public class GroupNettyClientHandler extends ChannelInboundHandlerAdapter {
                     }
                 }
             } else if (message.getOpCode() == 7) {
-                NettyMessage<AlarmDefine> AlarmDefineMessage = JSONObject.parseObject(String.valueOf(msg), new TypeReference<NettyMessage<AlarmDefine>>() {
+                NettyMessage<AlarmDefine> alarmDefineNettyMessage = JSONObject.parseObject(String.valueOf(msg), new TypeReference<NettyMessage<AlarmDefine>>() {
                 });
-                List<AlarmDefine> definesList = AlarmDefineMessage.getContent();
+                List<AlarmDefine> definesList = alarmDefineNettyMessage.getContent();
                 if (CollectionUtil.isNotEmpty(definesList)) {
                     alarmDefineService.listSomeAlarmDefine(definesList);
                 }
             } else if (message.getOpCode() == 10) {
-                NettyMessage<AlarmDefine> AlarmDefineMessage = JSONObject.parseObject(String.valueOf(msg), new TypeReference<NettyMessage<AlarmDefine>>() {
+                NettyMessage<AlarmDefine> alarmDefineNettyMessage = JSONObject.parseObject(String.valueOf(msg), new TypeReference<NettyMessage<AlarmDefine>>() {
                 });
-                List<AlarmDefine> definesList = AlarmDefineMessage.getContent();
+                List<AlarmDefine> definesList = alarmDefineNettyMessage.getContent();
                 if (CollectionUtil.isNotEmpty(definesList)) {
                     alarmDefineService.deleteAlarmDefine(definesList);
                 }
             }else if (message.getOpCode() == 8) {
-                log.info("-----报警记录id推送----[{}]",message);
+                log.info("云端完成报警记录创建");
+                log.info("返回报警记录id[{}]",message);
                 //{"id":"","objId":"","itemCode":""}  id为报警记录ID
+
                 List content = message.getContent();
                 if (CollectionUtil.isNotEmpty(content)) {
                     JSONObject parseObject = JSONObject.parseObject(JSONObject.toJSONString(content.get(0)));
-                    String defineId = parseObject.getString("itemCode") + "-" + parseObject.getString("objId");
-                    ZktAlarmRecordDO zktAlarmRecordDO = alarmRecordRepository.findById(defineId).orElse(new ZktAlarmRecordDO());
-                    zktAlarmRecordDO.setDefinitionId(defineId);
-                    zktAlarmRecordDO.setItemCode(parseObject.getString("itemCode"));
-                    zktAlarmRecordDO.setObjId(parseObject.getString("objId"));
-                    zktAlarmRecordDO.setAlarmId(parseObject.getString("id"));
-                    zktAlarmRecordDO.setProjectId(parseObject.getString("projectId"));
-                    alarmRecordRepository.save(zktAlarmRecordDO);
+                    String alarmId = parseObject.getString("id");
+                    // 将alarmId放入缓存中,用于后续判断报警是否完成创建
+                    createdAlarmIdsCache.put(alarmId);
                 }
             }
             NettyMessage response = new NettyMessage(groupNettyClient.projectId);

+ 39 - 0
src/main/java/com/persagy/entity/AlarmRecordIdsCache.java

@@ -0,0 +1,39 @@
+package com.persagy.entity;
+
+
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.annotation.JSONField;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 缓存云端返回的报警记录id
+ */
+@ApiModel(value = "缓存报警记录id")
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Entity
+@Table(name = "alarm_record_ids_cache")
+public class AlarmRecordIdsCache implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * 报警记录ID
+     */
+    @Id
+    private String id;
+
+
+}

+ 5 - 2
src/main/java/com/persagy/init/InitRunner.java

@@ -2,6 +2,7 @@ package com.persagy.init;
 
 
 import com.googlecode.aviator.AviatorEvaluator;
+import com.persagy.cache.CreatedAlarmIdsCache;
 import com.persagy.client.GroupNettyClient;
 import com.persagy.client.WebSocketClientFactory;
 import com.persagy.service.AlarmQuartzService;
@@ -23,18 +24,20 @@ public class InitRunner implements CommandLineRunner {
 	private GroupNettyClient groupNettyClient;
 	@Autowired
 	AlarmQuartzService alarmQuartzService;
+	@Autowired
+	CreatedAlarmIdsCache createdAlarmIdsCache;
 
 
 	@Override
 	public void run(String... args) throws Exception {
+		// 已创建的报警id缓存初始化
+		createdAlarmIdsCache.init();
 		//5.0 开始引入了 LRU 缓存,可指定缓存的表达式个数,比如设置为最大 1 万个缓存结果:
 		AviatorEvaluator.getInstance().useLRUExpressionCache(10000);
 		//启动netty客户端,接受云端数据
 		groupNettyClient.start();
 		//启动websocket,接受IOT采集庶数据
 		webSocketClientFactory.retryOutCallWebSocketClient();
-		//
 		alarmQuartzService.initAlarmMessagehandler();
-
 	}
 }

+ 27 - 4
src/main/java/com/persagy/job/AlarmExpireJob.java

@@ -4,6 +4,7 @@ import cn.hutool.core.date.DatePattern;
 import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUtil;
 import com.persagy.cache.AlarmInfoCache;
+import com.persagy.cache.CreatedAlarmIdsCache;
 import com.persagy.client.GroupNettyClient;
 import com.persagy.entity.AlarmDefineState;
 import com.persagy.entity.AlarmRecord;
@@ -36,6 +37,8 @@ public class AlarmExpireJob extends QuartzJobBean {
     AlarmRecordRepository alarmRecordRepository;
     @Autowired
     AlarmInfoCache alarmInfoCache;
+    @Autowired
+    CreatedAlarmIdsCache createdAlarmIdsCache;
     /**
      * 报警记录信息详情
      */
@@ -98,6 +101,16 @@ public class AlarmExpireJob extends QuartzJobBean {
 
     private AtomicLong nums = new AtomicLong(1L);
 
+    /**
+     * @description: 执行恢复/过期定时任务
+     * @param: context
+     * @return: void
+     * @exception:
+     * @author: lixing
+     * @company: Persagy Technology Co.,Ltd
+     * @since: 2021/1/22 上午9:38
+     * @version: V1.0
+     */
     @Override
     protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
         try {
@@ -105,12 +118,17 @@ public class AlarmExpireJob extends QuartzJobBean {
             JobDataMap mergedJobDataMap = context.getMergedJobDataMap();
             log.info("定时任务开始{}", alarmRecord);
             log.info("定时任务为{}任务", jobType);
-            log.warn("refireCount:[{}],过期/恢复时间:[{}/{}],实际执行时间:[{}]", context.getRefireCount(), StringUtil.getString(expireTime), StringUtil.getString(endTime), DateUtil.format(context.getFireTime(), DatePattern.ISO8601_PATTERN));
+            log.warn("refireCount:[{}],过期/恢复时间:[{}/{}],实际执行时间:[{}]",
+                    context.getRefireCount(),
+                    StringUtil.getString(expireTime),
+                    StringUtil.getString(endTime),
+                    DateUtil.format(context.getFireTime(), DatePattern.ISO8601_PATTERN));
             if (StringUtils.isNotBlank(alarmRecord)) {
                 ZktAlarmRecordDO zktAlarmRecordDO = StringUtil.tranferItemToDTO(alarmRecord, ZktAlarmRecordDO.class);
-                // 立即过期的场景,过期的时候可能还没有报警记录ID,需要重新执行下
-                String alarmId = alarmRecordRepository.findById(zktAlarmRecordDO.getDefinitionId()).orElse(new ZktAlarmRecordDO()).getAlarmId();
-                if (StringUtil.isEmpty(alarmId)) {
+                String alarmId = zktAlarmRecordDO.getAlarmId();
+
+                // 立即过期的场景,过期的时候可能还没有报警记录ID,需要延迟重新执行
+                if (!createdAlarmIdsCache.contains(alarmId)) {
                     log.info("未获取到报警记录id, 定时任务将在5分钟后重新执行");
                     log.info("refire:[{}]", refire);
                     mergedJobDataMap.put("refire", String.valueOf(StringUtil.getInt(refire) + 1));
@@ -136,8 +154,13 @@ public class AlarmExpireJob extends QuartzJobBean {
                 //{"id","123", "state":1, "groupCode":"wd", "projectId":"Pj123"}
                 log.info("定时任务执行完成,向云端推送{}消息", jobType);
                 groupNettyClient.sendMessage(nettyMessage.toString());
+
+                // 删除缓存中报警id
+                createdAlarmIdsCache.remove(alarmId);
+
                 //已经过期的时候删除掉这条报警定义了,保证不会再次产生报警
                 AlarmDefineState alarmState = new AlarmDefineState(defineId);
+                alarmState.setAlarmStartTime("");
                 alarmInfoCache.setAlarmState(defineId, alarmState);
                 if (alarmRecordRepository.existsById(zktAlarmRecordDO.getDefinitionId())) {
                     alarmRecordRepository.deleteById(zktAlarmRecordDO.getDefinitionId());

+ 12 - 0
src/main/java/com/persagy/repository/AlarmRecordIdsCacheRepository.java

@@ -0,0 +1,12 @@
+package com.persagy.repository;
+
+import com.persagy.entity.AlarmRecordIdsCache;
+import com.persagy.entity.ZktAlarmRecordDO;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.PagingAndSortingRepository;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface AlarmRecordIdsCacheRepository extends PagingAndSortingRepository<AlarmRecordIdsCache, String> {
+}

+ 66 - 40
src/main/java/com/persagy/service/impl/AlarmHandleServiceImpl.java

@@ -6,6 +6,7 @@ import com.google.common.collect.Lists;
 import com.googlecode.aviator.AviatorEvaluator;
 import com.googlecode.aviator.Expression;
 import com.persagy.cache.AlarmInfoCache;
+import com.persagy.cache.CreatedAlarmIdsCache;
 import com.persagy.cache.CurrentDataCache;
 import com.persagy.client.GroupNettyClient;
 import com.persagy.entity.*;
@@ -24,7 +25,6 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
-import javax.transaction.Transactional;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
@@ -51,6 +51,8 @@ public class AlarmHandleServiceImpl implements AlarmHandleService {
     AlarmQuartzService alarmQuartzService;
     @Autowired
     AlarmRecordRepository alarmRecordRepository;
+    @Autowired
+    CreatedAlarmIdsCache createdAlarmIdsCache;
     /**
      * 集团编码
      */
@@ -73,7 +75,6 @@ public class AlarmHandleServiceImpl implements AlarmHandleService {
      * @version: V1.0
      */
     @Override
-    @Transactional
     public void handleIOTData(String msg) throws SchedulerException, InterruptedException {
         log.info("接收到采集值:[{}]", msg);
         String[] split = msg.split(";");
@@ -93,13 +94,14 @@ public class AlarmHandleServiceImpl implements AlarmHandleService {
                 List<AlarmDefine> alarmDefines = alarmInfoCache.getAlarmDefinitionIdByMeterFuncId(meterId, funcId);
                 for (AlarmDefine alarmDefine : alarmDefines) {
                     Condition condition = alarmDefine.getCondition();
+                    String defineId = AlarmInfoCache.getAlarmDefineId(alarmDefine);
+                    log.info("defineId: [{}]", defineId);
                     List<JSONObject> codeDetail = condition.getInfoCodes();
                     boolean match = codeDetail.stream().allMatch(
                             p -> currentDataCache.hasKey(p.getString("meterId"), p.getString("funcId"))
                     );
                     //报警定义的所有信息点都有采集数值,具备判断条件
                     if (match) {
-                        String defineId = AlarmInfoCache.getAlarmDefineId(alarmDefine);
                         String trigger = condition.getTrigger();
                         String end = condition.getEnd();
                         HashMap<String, Object> paramMap = new HashMap<>();
@@ -112,7 +114,6 @@ public class AlarmHandleServiceImpl implements AlarmHandleService {
                         Expression endExp = AviatorEvaluator.compile(end, true);
                         Boolean triggerResult = (Boolean) triggerExp.execute(paramMap);
                         Boolean endResult = (Boolean) endExp.execute(paramMap);
-                        log.info("defineId: [{}]", defineId);
                         log.info("triggerResult:[{}],endResult:[{}]", triggerResult, endResult);
                         if (triggerResult && endResult) {
                             log.warn("报警触发条件和报警恢复条件同时满足,请检查,报警定义详情【{}】", alarmDefine.toString());
@@ -122,20 +123,20 @@ public class AlarmHandleServiceImpl implements AlarmHandleService {
                             //报警产生值满足(这里的满足不考虑报警持续时间)
                             if (triggerResult) {
                                 log.info("满足报警条件");
-//                                log.info("--" + alarmDefine.toString());
-//                                log.info("--" + JSONObject.toJSONString(paramMap));
+                                //                                log.info("--" + alarmDefine.toString());
+                                //                                log.info("--" + JSONObject.toJSONString(paramMap));
                                 //报警的时候不考虑报警恢复,因为同时报警和报警恢复是不应该出现的
                                 handlerNowDataAlarm(alarmDefine, dataTime, paramMap);
                             } else {
                                 log.info("不满足报警条件");
-//                                log.info("--" + alarmDefine.toString());
-//                                log.info("--" + JSONObject.toJSONString(paramMap));
+                                //                                log.info("--" + alarmDefine.toString());
+                                //                                log.info("--" + JSONObject.toJSONString(paramMap));
                                 //当前数据正常
                                 handlerNowDataNormal(alarmDefine, dataTime, endResult, paramMap);
                             }
                         }
                     } else {
-                        log.warn("部分信息点没有数值:[{}]", codeDetail);
+                        log.warn("部分信息点没有数值");
                     }
                 }
             }
@@ -215,27 +216,29 @@ public class AlarmHandleServiceImpl implements AlarmHandleService {
             }
 
             /* 超过报警恢复设置的持续时间 */
-            // 边缘端记录报警恢复消息
-            ZktAlarmRecordDO alarmRecordDO = upsertZktAlarmRecordWhenAlarmSuspend(alarmDefine, dataTime, paramMap);
-
-            String alarmId = alarmRecordDO.getAlarmId();
-            //报警恢复参数
-            AlarmRecord alarmResumeRecord = AlarmRecord.builder()
-                    .state(2)
-                    .groupCode(groupCode)
-                    .projectId(alarmDefine.getProjectId())
-                    .endTime(DateUtils.parseDate(dataTime))
-                    .endInfo(JSONObject.toJSONString(paramMap))
-                    .build();
             log.info("报警恢复持续时间大于设定时间:[{}]>[{}]", alarmSuspendLastTime, uphold);
-            //如果有报警ID,直接报警恢复
-            if (StringUtils.isNotEmpty(alarmId)) {
+            // 拼装恢复后的边缘端报警信息
+            ZktAlarmRecordDO alarmRecordDO = getZktAlarmRecordDOWhenAlarmSuspend(defineId, dataTime, paramMap);
+            String alarmId = alarmRecordDO.getAlarmId();
+            // 如果云端已经完成报警记录的创建,直接发送更新报警状态消息,并删除数据库中的报警信息
+            if (createdAlarmIdsCache.contains(alarmId)) {
+                deleteZktAlarmRecordWhenAlarmSuspend(defineId);
+                //报警恢复参数
+                AlarmRecord alarmResumeRecord = AlarmRecord.builder()
+                        .state(2)
+                        .groupCode(groupCode)
+                        .projectId(alarmDefine.getProjectId())
+                        .endTime(DateUtils.parseDate(dataTime))
+                        .endInfo(JSONObject.toJSONString(paramMap))
+                        .build();
                 alarmResumeRecord.setId(alarmId);
                 NettyMessage<AlarmRecord> nettyMessage = new NettyMessage<>(6, alarmDefine.getProjectId());
                 nettyMessage.setContent(Collections.singletonList(alarmResumeRecord));
                 //{"id","123", "state":1, "groupCode":"wd", "projectId":"Pj123","alarmSuspendStartTime":"","endInfo":""}
                 groupNettyClient.sendMessage(nettyMessage.toString());
                 log.error("产生一条报警恢复消息: [{}]", nettyMessage.toString());
+                // 报警恢复后,从缓存中移除报警id
+                createdAlarmIdsCache.remove(alarmId);
             } else {
                 log.info("未获取到报警记录id, 3分钟后重试发送报警恢复消息");
                 //如果没有报警ID,定时任务再次测试
@@ -248,22 +251,20 @@ public class AlarmHandleServiceImpl implements AlarmHandleService {
                 //恢复
                 jobDataMap.put("state", "2");
                 log.info("发送恢复消息的任务参数:{}", JSONObject.toJSONString(jobDataMap));
-                String jobName = defineId;
                 ExpireAlarmMessage em = new ExpireAlarmMessage();
                 //恢复消息
                 em.setType("1");
                 em.setStartTime(DateUtil.offsetMinute(new Date(), 3).toJdkDate());
                 em.setJobDataMap(jobDataMap);
-                em.setJobName(jobName);
+                em.setJobName(alarmId);
                 em.setJobGroupName("resume");
                 ExpireAlarmQueue.getExpireAlarmMessageQueue().produce(em);
             }
 
-            String jobName = AlarmInfoCache.getAlarmDefineId(alarmDefine);
             ExpireAlarmMessage em = new ExpireAlarmMessage();
             //取消过期消息
             em.setType("2");
-            em.setJobName(jobName);
+            em.setJobName(alarmId);
             em.setJobGroupName("expire");
             ExpireAlarmQueue.getExpireAlarmMessageQueue().produce(em);
             //报警恢复,报警状态重置回默认
@@ -273,8 +274,23 @@ public class AlarmHandleServiceImpl implements AlarmHandleService {
     }
 
     /**
-     * @description: 当报警恢复时边缘端保存/更新报警信息
-     * @param: alarmDefine
+     * @description: 当报警恢复时边缘端删除报警信息
+     * @param: defineId 报警定义id
+     * @exception:
+     * @author: lixing
+     * @company: Persagy Technology Co.,Ltd
+     * @since: 2021/1/13 下午5:11
+     * @version: V1.0
+     */
+    private void deleteZktAlarmRecordWhenAlarmSuspend(String defineId) {
+        if(alarmRecordRepository.existsById(defineId)) {
+            alarmRecordRepository.deleteById(defineId);
+        }
+    }
+
+    /**
+     * @description: 当报警恢复时拼装边缘端报警信息
+     * @param: defineId 报警定义id
      * @param: dataTime
      * @param: paramMap
      * @return: com.persagy.entity.ZktAlarmRecordDO
@@ -284,12 +300,16 @@ public class AlarmHandleServiceImpl implements AlarmHandleService {
      * @since: 2021/1/13 下午5:11
      * @version: V1.0
      */
-    private ZktAlarmRecordDO upsertZktAlarmRecordWhenAlarmSuspend(AlarmDefine alarmDefine, String dataTime, HashMap<String, Object> paramMap) {
-        ZktAlarmRecordDO alarmRecordDO = initZktAlarmRecordDO(alarmDefine);
+    private ZktAlarmRecordDO getZktAlarmRecordDOWhenAlarmSuspend(String defineId, String dataTime, HashMap<String, Object> paramMap) {
+        if (!alarmRecordRepository.existsById(defineId)) {
+            log.error("根据报警定义id[{}]未获取到边缘端报警信息", defineId);
+            throw new RuntimeException("根据报警定义id" + defineId + "未获取到边缘端报警信息");
+        }
+        Optional<ZktAlarmRecordDO> recordOptional = alarmRecordRepository.findById(defineId);
+        ZktAlarmRecordDO alarmRecordDO = recordOptional.get();
         alarmRecordDO.setState("2");
         alarmRecordDO.setEndTime(DateUtils.parseDate(dataTime));
         alarmRecordDO.setEndInfo(JSONObject.toJSONString(paramMap));
-        alarmRecordRepository.save(alarmRecordDO);
         return alarmRecordDO;
     }
 
@@ -372,12 +392,13 @@ public class AlarmHandleServiceImpl implements AlarmHandleService {
                 log.info("设定的持续时间:[{}]", condition.getTriggerUphold());
                 if (alarmLastTime >= condition.getTriggerUphold()) {
                     log.info("报警持续时间大于设定的持续时间,产生一条报警");
+                    String alarmId = StringUtil.getUUID();
                     // 边缘端保存报警信息
-                    upsertZktAlarmRecordWhenAlarmStart(alarmDefine, dataTime);
+                    saveZktAlarmRecordWhenAlarmStart(alarmId, alarmDefine, dataTime);
                     // 报警定义状态更新为未处理
                     alarmDefineState.setState(AlarmDefineState.State.NOT_DEAL.getType());
                     // 发送创建报警记录的消息
-                    sendCreateAlarmRecordMessage(alarmDefine, dataTime, paramMap,
+                    sendCreateAlarmRecordMessage(alarmId, alarmDefine, dataTime, paramMap,
                             DateUtils.localDateTime2Date(expireDateTime));
 
                     //有过期时间,生成报警过期消息
@@ -385,7 +406,7 @@ public class AlarmHandleServiceImpl implements AlarmHandleService {
                         //过期时间
                         log.info("产生一条定时过期报警消息, 过期时间为:{}", expireDateTime);
                         // 创建一条过期任务
-                        createExpireJob(alarmDefine, alarmDefineState, expireDateTime);
+                        createExpireJob(alarmId, alarmDefine, alarmDefineState, expireDateTime);
                     }
                 }
             }
@@ -427,6 +448,7 @@ public class AlarmHandleServiceImpl implements AlarmHandleService {
 
     /**
      * @description: 创建过期任务
+     * @param: alarmId 报警id
      * @param: alarmDefine 报警定义
      * @param: alarmDefineState 报警定义状态对象
      * @param: expireDateTime 过期时间
@@ -437,9 +459,8 @@ public class AlarmHandleServiceImpl implements AlarmHandleService {
      * @since: 2021/1/13 下午3:39
      * @version: V1.0
      */
-    private void createExpireJob(AlarmDefine alarmDefine, AlarmDefineState alarmDefineState, LocalDateTime expireDateTime) throws InterruptedException {
+    private void createExpireJob(String alarmId, AlarmDefine alarmDefine, AlarmDefineState alarmDefineState, LocalDateTime expireDateTime) throws InterruptedException {
         String defineId = AlarmInfoCache.getAlarmDefineId(alarmDefine);
-        String alarmId = alarmRecordRepository.findById(defineId).orElse(new ZktAlarmRecordDO()).getAlarmId();
         ZktAlarmRecordDO alarmRecordDO = ZktAlarmRecordDO.builder()
                 .alarmTime(alarmDefineState.getAlarmStartTime())
                 .effectEndTime(DateUtils.format(expireDateTime))
@@ -463,13 +484,14 @@ public class AlarmHandleServiceImpl implements AlarmHandleService {
         em.setType("1");
         em.setStartTime(DateUtils.localDateTime2Date(expireDateTime));
         em.setJobDataMap(jobDataMap);
-        em.setJobName(defineId);
+        em.setJobName(alarmId);
         em.setJobGroupName("expire");
         ExpireAlarmQueue.getExpireAlarmMessageQueue().produce(em);
     }
 
     /**
-     * @description: 当报警开始时边缘端保存/更新报警信息
+     * @description: 当报警开始时边缘端保存报警信息
+     * @param: alarmId 报警记录id
      * @param: alarmDefine 报警定义
      * @return: com.persagy.entity.ZktAlarmRecordDO
      * @exception:
@@ -478,8 +500,9 @@ public class AlarmHandleServiceImpl implements AlarmHandleService {
      * @since: 2021/1/8 下午5:55
      * @version: V1.0
      */
-    private ZktAlarmRecordDO upsertZktAlarmRecordWhenAlarmStart(AlarmDefine alarmDefine, String alarmTime) {
+    private ZktAlarmRecordDO saveZktAlarmRecordWhenAlarmStart(String alarmId, AlarmDefine alarmDefine, String alarmTime) {
         ZktAlarmRecordDO zktAlarmRecordDO = initZktAlarmRecordDO(alarmDefine);
+        zktAlarmRecordDO.setAlarmId(alarmId);
         zktAlarmRecordDO.setState("1");
         zktAlarmRecordDO.setAlarmTime(alarmTime);
         alarmRecordRepository.save(zktAlarmRecordDO);
@@ -509,6 +532,7 @@ public class AlarmHandleServiceImpl implements AlarmHandleService {
 
     /**
      * @description: 发送创建报警记录消息
+     * @param: alarmId 报警id
      * @param: alarmDefine 报警定义
      * @param: triggerTime 触发时间
      * @param: triggerInfo 触发值
@@ -521,10 +545,12 @@ public class AlarmHandleServiceImpl implements AlarmHandleService {
      * @version: V1.0
      */
     private void sendCreateAlarmRecordMessage(
+            String alarmId,
             AlarmDefine alarmDefine, String triggerTime,
             HashMap<String, Object> triggerInfo, Date expireDate) throws InterruptedException {
         Condition condition = alarmDefine.getCondition();
         AlarmRecord alarmRecord = AlarmRecord.builder()
+                .id(alarmId)
                 .category(alarmDefine.getCategory())
                 .concern(alarmDefine.getConcern())
                 .level(alarmDefine.getLevel())

+ 14 - 8
src/main/java/com/persagy/service/impl/AlarmQuartzServiceImpl.java

@@ -35,22 +35,28 @@ public class AlarmQuartzServiceImpl implements AlarmQuartzService {
 
     @Override
     public void initAlarmMessagehandler() {
+
+        System.out.println("--init--");
+        //启动后先休息20秒,这样报警netty  websocket  quartz都启动了
         try {
-            System.out.println("--init--");
-            //启动后先休息20秒,这样报警netty  websocket  quartz都启动了
             Thread.sleep(20000);
-            while (true) {
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+        while (true) {
+            try {
                 ExpireAlarmMessage expireAlarmMessage = ExpireAlarmQueue.getExpireAlarmMessageQueue().consume();
-                log.info("剩余过期消息总数:{}", ExpireAlarmQueue.getExpireAlarmMessageQueue().size());
+                log.info("剩余消息总数:{}", ExpireAlarmQueue.getExpireAlarmMessageQueue().size());
                 if ("1".equals(expireAlarmMessage.getType())) {
                     addExpireJob(expireAlarmMessage.getStartTime(), expireAlarmMessage.getJobName(), expireAlarmMessage.getJobGroupName(), expireAlarmMessage.getJobDataMap());
                 } else if ("2".equals(expireAlarmMessage.getType())) {
                     deleteExpireJob(expireAlarmMessage.getJobName(), expireAlarmMessage.getJobGroupName());
                 }
+            } catch (Exception e) {
+                log.error("报警过期消息队列消费失败", e);
             }
-        } catch (Exception e) {
-            log.error("报警过期消息队列消费失败", e);
         }
+
     }
 
     /**
@@ -69,7 +75,7 @@ public class AlarmQuartzServiceImpl implements AlarmQuartzService {
             log.error("执行时间【{}】为历史时间,继续添加", DateUtils.formatDate(startTime));
         }
         JobKey jobKey = new JobKey(jobName, jobGroupName);
-        log.info("恢复/过期任务jobKey: [{}]", jobKey);
+        log.info("新增恢复/过期任务jobKey: [{}]", jobKey);
         JobDetail jobDetail = JobBuilder.newJob(AlarmExpireJob.class).withIdentity(jobName, jobGroupName).requestRecovery().build();
         Trigger trigger = TriggerBuilder.newTrigger().startAt(startTime)
                 .withIdentity("trigger_" + jobName, jobGroupName)
@@ -153,7 +159,7 @@ public class AlarmQuartzServiceImpl implements AlarmQuartzService {
             log.info("移除过期任务:[{}]", jobKey);
             quartzScheduler.deleteJob(jobKey);
         } else {
-            log.info("要移除过期任务不存在!可能已经执行完成~");
+            log.info("要移除过期任务[{}]不存在!可能已经执行完成~", jobKey);
         }
         return "success!";
     }

+ 2 - 0
src/main/resources/quartz.properties

@@ -33,6 +33,7 @@ org.quartz.jobStore.clusterCheckinInterval=10000
 org.quartz.jobStore.useProperties=true
 #在被认为“misfired”(失火)之前,调度程序将“tolerate(容忍)”一个Triggers(触发器)将其下一个启动时间通过的毫秒数。默认值(如果您在配置中未输入此属性)为60000(60秒)
 org.quartz.jobStore.misfireThreshold=600000
+org.quartz.jobStore.txIsolationLevelSerializable=false
 #
 ##默认C3P0方式配置数据库,connectionProvider方式可以指定,但是高级属性配置很不方便,不推荐
 #org.quartz.jobStore.dataSource = qzDS
@@ -42,3 +43,4 @@ org.quartz.jobStore.misfireThreshold=600000
 #org.quartz.dataSource.qzDS.password = 123456
 #org.quartz.dataSource.qzDS.maxConnections = 100
 #org.quartz.dataSource.qzDS.connectionProvider.class = com.persagy.plan.config.DruidConnectionProvider
+

+ 205 - 171
src/main/resources/zkt_alarm_tables_mysql_innodb.sql

@@ -18,178 +18,212 @@ DROP TABLE IF EXISTS ZKT_ALARM_TRIGGERS;
 DROP TABLE IF EXISTS ZKT_ALARM_JOB_DETAILS;
 DROP TABLE IF EXISTS ZKT_ALARM_CALENDARS;
 DROP TABLE IF EXISTS `zkt_alarm_record`;
-
-
-CREATE TABLE ZKT_ALARM_JOB_DETAILS(
-SCHED_NAME VARCHAR(120) NOT NULL,
-JOB_NAME VARCHAR(190) NOT NULL,
-JOB_GROUP VARCHAR(190) NOT NULL,
-DESCRIPTION VARCHAR(250) NULL,
-JOB_CLASS_NAME VARCHAR(250) NOT NULL,
-IS_DURABLE VARCHAR(1) NOT NULL,
-IS_NONCONCURRENT VARCHAR(1) NOT NULL,
-IS_UPDATE_DATA VARCHAR(1) NOT NULL,
-REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
-JOB_DATA BLOB NULL,
-PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP))
-ENGINE=InnoDB;
-
-CREATE TABLE ZKT_ALARM_TRIGGERS (
-SCHED_NAME VARCHAR(120) NOT NULL,
-TRIGGER_NAME VARCHAR(190) NOT NULL,
-TRIGGER_GROUP VARCHAR(190) NOT NULL,
-JOB_NAME VARCHAR(190) NOT NULL,
-JOB_GROUP VARCHAR(190) NOT NULL,
-DESCRIPTION VARCHAR(250) NULL,
-NEXT_FIRE_TIME BIGINT(13) NULL,
-PREV_FIRE_TIME BIGINT(13) NULL,
-PRIORITY INTEGER NULL,
-TRIGGER_STATE VARCHAR(16) NOT NULL,
-TRIGGER_TYPE VARCHAR(8) NOT NULL,
-START_TIME BIGINT(13) NOT NULL,
-END_TIME BIGINT(13) NULL,
-CALENDAR_NAME VARCHAR(190) NULL,
-MISFIRE_INSTR SMALLINT(2) NULL,
-JOB_DATA BLOB NULL,
-PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
-FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
-REFERENCES ZKT_ALARM_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP))
-ENGINE=InnoDB;
-
-CREATE TABLE ZKT_ALARM_SIMPLE_TRIGGERS (
-SCHED_NAME VARCHAR(120) NOT NULL,
-TRIGGER_NAME VARCHAR(190) NOT NULL,
-TRIGGER_GROUP VARCHAR(190) NOT NULL,
-REPEAT_COUNT BIGINT(7) NOT NULL,
-REPEAT_INTERVAL BIGINT(12) NOT NULL,
-TIMES_TRIGGERED BIGINT(10) NOT NULL,
-PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
-FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
-REFERENCES ZKT_ALARM_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
-ENGINE=InnoDB;
-
-CREATE TABLE ZKT_ALARM_CRON_TRIGGERS (
-SCHED_NAME VARCHAR(120) NOT NULL,
-TRIGGER_NAME VARCHAR(190) NOT NULL,
-TRIGGER_GROUP VARCHAR(190) NOT NULL,
-CRON_EXPRESSION VARCHAR(120) NOT NULL,
-TIME_ZONE_ID VARCHAR(80),
-PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
-FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
-REFERENCES ZKT_ALARM_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
-ENGINE=InnoDB;
+DROP TABLE IF EXISTS `alarm_record_ids_cache`;
+
+
+CREATE TABLE ZKT_ALARM_JOB_DETAILS
+(
+    SCHED_NAME        VARCHAR(120) NOT NULL,
+    JOB_NAME          VARCHAR(190) NOT NULL,
+    JOB_GROUP         VARCHAR(190) NOT NULL,
+    DESCRIPTION       VARCHAR(250) NULL,
+    JOB_CLASS_NAME    VARCHAR(250) NOT NULL,
+    IS_DURABLE        VARCHAR(1)   NOT NULL,
+    IS_NONCONCURRENT  VARCHAR(1)   NOT NULL,
+    IS_UPDATE_DATA    VARCHAR(1)   NOT NULL,
+    REQUESTS_RECOVERY VARCHAR(1)   NOT NULL,
+    JOB_DATA          BLOB         NULL,
+    PRIMARY KEY (SCHED_NAME, JOB_NAME, JOB_GROUP)
+)
+    ENGINE = InnoDB;
+
+CREATE TABLE ZKT_ALARM_TRIGGERS
+(
+    SCHED_NAME     VARCHAR(120) NOT NULL,
+    TRIGGER_NAME   VARCHAR(190) NOT NULL,
+    TRIGGER_GROUP  VARCHAR(190) NOT NULL,
+    JOB_NAME       VARCHAR(190) NOT NULL,
+    JOB_GROUP      VARCHAR(190) NOT NULL,
+    DESCRIPTION    VARCHAR(250) NULL,
+    NEXT_FIRE_TIME BIGINT(13)   NULL,
+    PREV_FIRE_TIME BIGINT(13)   NULL,
+    PRIORITY       INTEGER      NULL,
+    TRIGGER_STATE  VARCHAR(16)  NOT NULL,
+    TRIGGER_TYPE   VARCHAR(8)   NOT NULL,
+    START_TIME     BIGINT(13)   NOT NULL,
+    END_TIME       BIGINT(13)   NULL,
+    CALENDAR_NAME  VARCHAR(190) NULL,
+    MISFIRE_INSTR  SMALLINT(2)  NULL,
+    JOB_DATA       BLOB         NULL,
+    PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
+    FOREIGN KEY (SCHED_NAME, JOB_NAME, JOB_GROUP)
+        REFERENCES ZKT_ALARM_JOB_DETAILS (SCHED_NAME, JOB_NAME, JOB_GROUP)
+)
+    ENGINE = InnoDB;
+
+CREATE TABLE ZKT_ALARM_SIMPLE_TRIGGERS
+(
+    SCHED_NAME      VARCHAR(120) NOT NULL,
+    TRIGGER_NAME    VARCHAR(190) NOT NULL,
+    TRIGGER_GROUP   VARCHAR(190) NOT NULL,
+    REPEAT_COUNT    BIGINT(7)    NOT NULL,
+    REPEAT_INTERVAL BIGINT(12)   NOT NULL,
+    TIMES_TRIGGERED BIGINT(10)   NOT NULL,
+    PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
+    FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
+        REFERENCES ZKT_ALARM_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
+)
+    ENGINE = InnoDB;
+
+CREATE TABLE ZKT_ALARM_CRON_TRIGGERS
+(
+    SCHED_NAME      VARCHAR(120) NOT NULL,
+    TRIGGER_NAME    VARCHAR(190) NOT NULL,
+    TRIGGER_GROUP   VARCHAR(190) NOT NULL,
+    CRON_EXPRESSION VARCHAR(120) NOT NULL,
+    TIME_ZONE_ID    VARCHAR(80),
+    PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
+    FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
+        REFERENCES ZKT_ALARM_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
+)
+    ENGINE = InnoDB;
 
 CREATE TABLE ZKT_ALARM_SIMPROP_TRIGGERS
-  (
-    SCHED_NAME VARCHAR(120) NOT NULL,
-    TRIGGER_NAME VARCHAR(190) NOT NULL,
+(
+    SCHED_NAME    VARCHAR(120)   NOT NULL,
+    TRIGGER_NAME  VARCHAR(190)   NOT NULL,
+    TRIGGER_GROUP VARCHAR(190)   NOT NULL,
+    STR_PROP_1    VARCHAR(512)   NULL,
+    STR_PROP_2    VARCHAR(512)   NULL,
+    STR_PROP_3    VARCHAR(512)   NULL,
+    INT_PROP_1    INT            NULL,
+    INT_PROP_2    INT            NULL,
+    LONG_PROP_1   BIGINT         NULL,
+    LONG_PROP_2   BIGINT         NULL,
+    DEC_PROP_1    NUMERIC(13, 4) NULL,
+    DEC_PROP_2    NUMERIC(13, 4) NULL,
+    BOOL_PROP_1   VARCHAR(1)     NULL,
+    BOOL_PROP_2   VARCHAR(1)     NULL,
+    PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
+    FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
+        REFERENCES ZKT_ALARM_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
+)
+    ENGINE = InnoDB;
+
+CREATE TABLE ZKT_ALARM_BLOB_TRIGGERS
+(
+    SCHED_NAME    VARCHAR(120) NOT NULL,
+    TRIGGER_NAME  VARCHAR(190) NOT NULL,
     TRIGGER_GROUP VARCHAR(190) NOT NULL,
-    STR_PROP_1 VARCHAR(512) NULL,
-    STR_PROP_2 VARCHAR(512) NULL,
-    STR_PROP_3 VARCHAR(512) NULL,
-    INT_PROP_1 INT NULL,
-    INT_PROP_2 INT NULL,
-    LONG_PROP_1 BIGINT NULL,
-    LONG_PROP_2 BIGINT NULL,
-    DEC_PROP_1 NUMERIC(13,4) NULL,
-    DEC_PROP_2 NUMERIC(13,4) NULL,
-    BOOL_PROP_1 VARCHAR(1) NULL,
-    BOOL_PROP_2 VARCHAR(1) NULL,
-    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
-    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
-    REFERENCES ZKT_ALARM_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
-ENGINE=InnoDB;
-
-CREATE TABLE ZKT_ALARM_BLOB_TRIGGERS (
-SCHED_NAME VARCHAR(120) NOT NULL,
-TRIGGER_NAME VARCHAR(190) NOT NULL,
-TRIGGER_GROUP VARCHAR(190) NOT NULL,
-BLOB_DATA BLOB NULL,
-PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
-INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),
-FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
-REFERENCES ZKT_ALARM_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
-ENGINE=InnoDB;
-
-CREATE TABLE ZKT_ALARM_CALENDARS (
-SCHED_NAME VARCHAR(120) NOT NULL,
-CALENDAR_NAME VARCHAR(190) NOT NULL,
-CALENDAR BLOB NOT NULL,
-PRIMARY KEY (SCHED_NAME,CALENDAR_NAME))
-ENGINE=InnoDB;
-
-CREATE TABLE ZKT_ALARM_PAUSED_TRIGGER_GRPS (
-SCHED_NAME VARCHAR(120) NOT NULL,
-TRIGGER_GROUP VARCHAR(190) NOT NULL,
-PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))
-ENGINE=InnoDB;
-
-CREATE TABLE ZKT_ALARM_FIRED_TRIGGERS (
-SCHED_NAME VARCHAR(120) NOT NULL,
-ENTRY_ID VARCHAR(95) NOT NULL,
-TRIGGER_NAME VARCHAR(190) NOT NULL,
-TRIGGER_GROUP VARCHAR(190) NOT NULL,
-INSTANCE_NAME VARCHAR(190) NOT NULL,
-FIRED_TIME BIGINT(13) NOT NULL,
-SCHED_TIME BIGINT(13) NOT NULL,
-PRIORITY INTEGER NOT NULL,
-STATE VARCHAR(16) NOT NULL,
-JOB_NAME VARCHAR(190) NULL,
-JOB_GROUP VARCHAR(190) NULL,
-IS_NONCONCURRENT VARCHAR(1) NULL,
-REQUESTS_RECOVERY VARCHAR(1) NULL,
-PRIMARY KEY (SCHED_NAME,ENTRY_ID))
-ENGINE=InnoDB;
-
-CREATE TABLE ZKT_ALARM_SCHEDULER_STATE (
-SCHED_NAME VARCHAR(120) NOT NULL,
-INSTANCE_NAME VARCHAR(190) NOT NULL,
-LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
-CHECKIN_INTERVAL BIGINT(13) NOT NULL,
-PRIMARY KEY (SCHED_NAME,INSTANCE_NAME))
-ENGINE=InnoDB;
-
-CREATE TABLE ZKT_ALARM_LOCKS (
-SCHED_NAME VARCHAR(120) NOT NULL,
-LOCK_NAME VARCHAR(40) NOT NULL,
-PRIMARY KEY (SCHED_NAME,LOCK_NAME))
-ENGINE=InnoDB;
-
-CREATE INDEX IDX_ZKT_ALARM_J_REQ_RECOVERY ON ZKT_ALARM_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);
-CREATE INDEX IDX_ZKT_ALARM_J_GRP ON ZKT_ALARM_JOB_DETAILS(SCHED_NAME,JOB_GROUP);
-
-CREATE INDEX IDX_ZKT_ALARM_T_J ON ZKT_ALARM_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
-CREATE INDEX IDX_ZKT_ALARM_T_JG ON ZKT_ALARM_TRIGGERS(SCHED_NAME,JOB_GROUP);
-CREATE INDEX IDX_ZKT_ALARM_T_C ON ZKT_ALARM_TRIGGERS(SCHED_NAME,CALENDAR_NAME);
-CREATE INDEX IDX_ZKT_ALARM_T_G ON ZKT_ALARM_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
-CREATE INDEX IDX_ZKT_ALARM_T_STATE ON ZKT_ALARM_TRIGGERS(SCHED_NAME,TRIGGER_STATE);
-CREATE INDEX IDX_ZKT_ALARM_T_N_STATE ON ZKT_ALARM_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);
-CREATE INDEX IDX_ZKT_ALARM_T_N_G_STATE ON ZKT_ALARM_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);
-CREATE INDEX IDX_ZKT_ALARM_T_NEXT_FIRE_TIME ON ZKT_ALARM_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);
-CREATE INDEX IDX_ZKT_ALARM_T_NFT_ST ON ZKT_ALARM_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);
-CREATE INDEX IDX_ZKT_ALARM_T_NFT_MISFIRE ON ZKT_ALARM_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);
-CREATE INDEX IDX_ZKT_ALARM_T_NFT_ST_MISFIRE ON ZKT_ALARM_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
-CREATE INDEX IDX_ZKT_ALARM_T_NFT_ST_MISFIRE_GRP ON ZKT_ALARM_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);
-
-CREATE INDEX IDX_ZKT_ALARM_FT_TRIG_INST_NAME ON ZKT_ALARM_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);
-CREATE INDEX IDX_ZKT_ALARM_FT_INST_JOB_REQ_RCVRY ON ZKT_ALARM_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);
-CREATE INDEX IDX_ZKT_ALARM_FT_J_G ON ZKT_ALARM_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
-CREATE INDEX IDX_ZKT_ALARM_FT_JG ON ZKT_ALARM_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);
-CREATE INDEX IDX_ZKT_ALARM_FT_T_G ON ZKT_ALARM_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);
-CREATE INDEX IDX_ZKT_ALARM_FT_TG ON ZKT_ALARM_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
-CREATE TABLE `zkt_alarm_record` (
-                                    `definition_id` varchar(100) NOT NULL DEFAULT '' COMMENT '报警定义ID',
-                                    `item_code` varchar(42) NOT NULL COMMENT '报警条目编码',
-                                    `obj_id` varchar(60) NOT NULL COMMENT '报警对象ID',
-                                    `state` varchar(10) DEFAULT NULL COMMENT '报警定义对应最新一条报警记录状态',
-                                    `alarm_id` varchar(42) DEFAULT NULL COMMENT '报警定义对应最新一条报警记录ID',
-                                    `alarm_time` varchar(20) DEFAULT NULL COMMENT '报警时间',
-                                    `effect_end_time` varchar(20) DEFAULT NULL COMMENT '报警生效结束时间(报警过期时间)',
-                                    `remark` varchar(255) DEFAULT NULL COMMENT '备注',
-                                    `name` varchar(100) DEFAULT NULL COMMENT '报警名称',
-                                    `end_info` json DEFAULT NULL COMMENT '报警结束值',
-                                    `end_time` datetime DEFAULT NULL COMMENT '报警结束时间',
-                                    `project_id` varchar(50) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '项目id',
-                                    PRIMARY KEY (`definition_id`) USING BTREE
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='报警记录ID';
+    BLOB_DATA     BLOB         NULL,
+    PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
+    INDEX (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
+    FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
+        REFERENCES ZKT_ALARM_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
+)
+    ENGINE = InnoDB;
+
+CREATE TABLE ZKT_ALARM_CALENDARS
+(
+    SCHED_NAME    VARCHAR(120) NOT NULL,
+    CALENDAR_NAME VARCHAR(190) NOT NULL,
+    CALENDAR      BLOB         NOT NULL,
+    PRIMARY KEY (SCHED_NAME, CALENDAR_NAME)
+)
+    ENGINE = InnoDB;
+
+CREATE TABLE ZKT_ALARM_PAUSED_TRIGGER_GRPS
+(
+    SCHED_NAME    VARCHAR(120) NOT NULL,
+    TRIGGER_GROUP VARCHAR(190) NOT NULL,
+    PRIMARY KEY (SCHED_NAME, TRIGGER_GROUP)
+)
+    ENGINE = InnoDB;
+
+CREATE TABLE ZKT_ALARM_FIRED_TRIGGERS
+(
+    SCHED_NAME        VARCHAR(120) NOT NULL,
+    ENTRY_ID          VARCHAR(95)  NOT NULL,
+    TRIGGER_NAME      VARCHAR(190) NOT NULL,
+    TRIGGER_GROUP     VARCHAR(190) NOT NULL,
+    INSTANCE_NAME     VARCHAR(190) NOT NULL,
+    FIRED_TIME        BIGINT(13)   NOT NULL,
+    SCHED_TIME        BIGINT(13)   NOT NULL,
+    PRIORITY          INTEGER      NOT NULL,
+    STATE             VARCHAR(16)  NOT NULL,
+    JOB_NAME          VARCHAR(190) NULL,
+    JOB_GROUP         VARCHAR(190) NULL,
+    IS_NONCONCURRENT  VARCHAR(1)   NULL,
+    REQUESTS_RECOVERY VARCHAR(1)   NULL,
+    PRIMARY KEY (SCHED_NAME, ENTRY_ID)
+)
+    ENGINE = InnoDB;
+
+CREATE TABLE ZKT_ALARM_SCHEDULER_STATE
+(
+    SCHED_NAME        VARCHAR(120) NOT NULL,
+    INSTANCE_NAME     VARCHAR(190) NOT NULL,
+    LAST_CHECKIN_TIME BIGINT(13)   NOT NULL,
+    CHECKIN_INTERVAL  BIGINT(13)   NOT NULL,
+    PRIMARY KEY (SCHED_NAME, INSTANCE_NAME)
+)
+    ENGINE = InnoDB;
+
+CREATE TABLE ZKT_ALARM_LOCKS
+(
+    SCHED_NAME VARCHAR(120) NOT NULL,
+    LOCK_NAME  VARCHAR(40)  NOT NULL,
+    PRIMARY KEY (SCHED_NAME, LOCK_NAME)
+)
+    ENGINE = InnoDB;
+
+CREATE INDEX IDX_ZKT_ALARM_J_REQ_RECOVERY ON ZKT_ALARM_JOB_DETAILS (SCHED_NAME, REQUESTS_RECOVERY);
+CREATE INDEX IDX_ZKT_ALARM_J_GRP ON ZKT_ALARM_JOB_DETAILS (SCHED_NAME, JOB_GROUP);
+
+CREATE INDEX IDX_ZKT_ALARM_T_J ON ZKT_ALARM_TRIGGERS (SCHED_NAME, JOB_NAME, JOB_GROUP);
+CREATE INDEX IDX_ZKT_ALARM_T_JG ON ZKT_ALARM_TRIGGERS (SCHED_NAME, JOB_GROUP);
+CREATE INDEX IDX_ZKT_ALARM_T_C ON ZKT_ALARM_TRIGGERS (SCHED_NAME, CALENDAR_NAME);
+CREATE INDEX IDX_ZKT_ALARM_T_G ON ZKT_ALARM_TRIGGERS (SCHED_NAME, TRIGGER_GROUP);
+CREATE INDEX IDX_ZKT_ALARM_T_STATE ON ZKT_ALARM_TRIGGERS (SCHED_NAME, TRIGGER_STATE);
+CREATE INDEX IDX_ZKT_ALARM_T_N_STATE ON ZKT_ALARM_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP, TRIGGER_STATE);
+CREATE INDEX IDX_ZKT_ALARM_T_N_G_STATE ON ZKT_ALARM_TRIGGERS (SCHED_NAME, TRIGGER_GROUP, TRIGGER_STATE);
+CREATE INDEX IDX_ZKT_ALARM_T_NEXT_FIRE_TIME ON ZKT_ALARM_TRIGGERS (SCHED_NAME, NEXT_FIRE_TIME);
+CREATE INDEX IDX_ZKT_ALARM_T_NFT_ST ON ZKT_ALARM_TRIGGERS (SCHED_NAME, TRIGGER_STATE, NEXT_FIRE_TIME);
+CREATE INDEX IDX_ZKT_ALARM_T_NFT_MISFIRE ON ZKT_ALARM_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME);
+CREATE INDEX IDX_ZKT_ALARM_T_NFT_ST_MISFIRE ON ZKT_ALARM_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME, TRIGGER_STATE);
+CREATE INDEX IDX_ZKT_ALARM_T_NFT_ST_MISFIRE_GRP ON ZKT_ALARM_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME,
+                                                                       TRIGGER_GROUP, TRIGGER_STATE);
+
+CREATE INDEX IDX_ZKT_ALARM_FT_TRIG_INST_NAME ON ZKT_ALARM_FIRED_TRIGGERS (SCHED_NAME, INSTANCE_NAME);
+CREATE INDEX IDX_ZKT_ALARM_FT_INST_JOB_REQ_RCVRY ON ZKT_ALARM_FIRED_TRIGGERS (SCHED_NAME, INSTANCE_NAME, REQUESTS_RECOVERY);
+CREATE INDEX IDX_ZKT_ALARM_FT_J_G ON ZKT_ALARM_FIRED_TRIGGERS (SCHED_NAME, JOB_NAME, JOB_GROUP);
+CREATE INDEX IDX_ZKT_ALARM_FT_JG ON ZKT_ALARM_FIRED_TRIGGERS (SCHED_NAME, JOB_GROUP);
+CREATE INDEX IDX_ZKT_ALARM_FT_T_G ON ZKT_ALARM_FIRED_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP);
+CREATE INDEX IDX_ZKT_ALARM_FT_TG ON ZKT_ALARM_FIRED_TRIGGERS (SCHED_NAME, TRIGGER_GROUP);
+CREATE TABLE `zkt_alarm_record`
+(
+    `definition_id`   varchar(100) NOT NULL             DEFAULT '' COMMENT '报警定义ID',
+    `item_code`       varchar(42)  NOT NULL COMMENT '报警条目编码',
+    `obj_id`          varchar(60)  NOT NULL COMMENT '报警对象ID',
+    `state`           varchar(10)                       DEFAULT NULL COMMENT '报警定义对应最新一条报警记录状态',
+    `alarm_id`        varchar(42)                       DEFAULT NULL COMMENT '报警定义对应最新一条报警记录ID',
+    `alarm_time`      varchar(20)                       DEFAULT NULL COMMENT '报警时间',
+    `effect_end_time` varchar(20)                       DEFAULT NULL COMMENT '报警生效结束时间(报警过期时间)',
+    `remark`          varchar(255)                      DEFAULT NULL COMMENT '备注',
+    `name`            varchar(100)                      DEFAULT NULL COMMENT '报警名称',
+    `end_info`        json                              DEFAULT NULL COMMENT '报警结束值',
+    `end_time`        datetime                          DEFAULT NULL COMMENT '报警结束时间',
+    `project_id`      varchar(50) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '项目id',
+    PRIMARY KEY (`definition_id`) USING BTREE
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8
+  ROW_FORMAT = DYNAMIC COMMENT ='报警记录ID';
+
+CREATE TABLE alarm_record_ids_cache
+(
+    `id` VARCHAR(50) NOT NULL,
+    PRIMARY KEY (`id`)
+)
+    ENGINE = InnoDB;
+
 commit;