Kaynağa Gözat

生成场景码逻辑 改为定时任务生成,保证redis中场景码数量不少于500,数据库中数量不少于1000

dengsixing 2 yıl önce
ebeveyn
işleme
a57caa8747

+ 31 - 0
src/main/java/com/fdkankan/contro/controller/TestController.java

@@ -0,0 +1,31 @@
+package com.fdkankan.contro.controller;
+
+import com.fdkankan.contro.service.IScene3dNumService;
+import com.fdkankan.web.response.ResultData;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ * TODO
+ * </p>
+ *
+ * @author dengsixing
+ * @since 2022/12/12
+ **/
+@RestController
+@RequestMapping("/test")
+public class TestController {
+
+    @Autowired
+    private IScene3dNumService scene3dNumService;
+
+    @GetMapping("/test")
+    public ResultData test() throws Exception {
+        String s = scene3dNumService.generateSceneNum(1);
+        return ResultData.ok(s);
+    }
+
+}

+ 3 - 3
src/main/java/com/fdkankan/contro/entity/Scene3dNum.java

@@ -40,8 +40,8 @@ public class Scene3dNum implements Serializable {
     /**
      * 记录的状态,A: 生效,I: 禁用
      */
-    @TableField("num")
-    private String num;
+    @TableField("code")
+    private String code;
 
     /**
      * 更新时间
@@ -59,7 +59,7 @@ public class Scene3dNum implements Serializable {
      * A正常,I删除
      */
     @TableField("rec_status")
-    @TableLogic("A")
+    @TableLogic(value = "A", delval = "I")
     private String recStatus;
 
 

+ 11 - 0
src/main/java/com/fdkankan/contro/schedule/ScheduleJob.java

@@ -1,5 +1,6 @@
 package com.fdkankan.contro.schedule;
 
+import com.fdkankan.contro.service.IScene3dNumService;
 import com.fdkankan.rabbitmq.util.RabbitMqProducer;
 import com.fdkankan.rubbersheeting.ScalingService;
 import lombok.extern.log4j.Log4j2;
@@ -23,6 +24,8 @@ public class ScheduleJob {
 
     @Value("${queue.modeling.modeling-call}")
     private String queueModelingCall;
+    @Autowired
+    private IScene3dNumService scene3dNumService;
 
 
     @Scheduled(cron = "${rocketmq.autoScaling.corn:0 0/5 8-21 * * ?}")
@@ -40,4 +43,12 @@ public class ScheduleJob {
             log.error(e.getMessage());
         }
     }
+
+    /**
+     * 定时生成场景码,间隔1小时执行一次,项目启动一秒后执行一次
+     */
+    @Scheduled(fixedDelay = 60*60*1000, initialDelay = 1000)
+    public void generateSceneNum() {
+        scene3dNumService.generateSceneNumHandler();
+    }
 }

+ 3 - 1
src/main/java/com/fdkankan/contro/service/IScene3dNumService.java

@@ -23,7 +23,9 @@ public interface IScene3dNumService extends IService<Scene3dNum> {
      * 从码池中取出一个场景码
      * @return
      */
-    String generateSceneNum(Integer cameraType);
+    String generateSceneNum(Integer cameraType) throws Exception;
+
+    void generateSceneNumHandler();
 
     /**
      * 批量生成场景码并放入码池

+ 76 - 59
src/main/java/com/fdkankan/contro/service/impl/Scene3dNumServiceImpl.java

@@ -1,5 +1,6 @@
 package com.fdkankan.contro.service.impl;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -11,6 +12,7 @@ import com.fdkankan.contro.entity.Scene3dNum;
 import com.fdkankan.contro.enums.CameraTypeEnum;
 import com.fdkankan.contro.mapper.IScene3dNumMapper;
 import com.fdkankan.contro.service.IScene3dNumService;
+import com.fdkankan.dingtalk.DingTalkSendUtils;
 import com.fdkankan.redis.constant.RedisKey;
 import com.fdkankan.redis.constant.RedisLockKey;
 import com.fdkankan.redis.util.RedisLockUtil;
@@ -18,6 +20,7 @@ import com.fdkankan.redis.util.RedisUtil;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
 import org.springframework.stereotype.Service;
 import org.springframework.util.CollectionUtils;
 
@@ -36,10 +39,16 @@ import java.util.stream.Collectors;
  * @author dengsixing
  * @since 2021-12-23
  */
+@RefreshScope
 @Slf4j
 @Service
 public class Scene3dNumServiceImpl extends ServiceImpl<IScene3dNumMapper, Scene3dNum> implements IScene3dNumService {
 
+    public static final String DINGTALK_MSG_PATTERN =
+        "**环境**: %s\n\n" +
+        "**标题**: %s\n\n" +
+        "**告警信息**: %s\n\n";
+
     @Autowired
     private RedisUtil redisUtil;
     @Autowired
@@ -47,54 +56,71 @@ public class Scene3dNumServiceImpl extends ServiceImpl<IScene3dNumMapper, Scene3
 
     @Value("${scene.num.cachePageSize:500}")
     private int cachePageSize;
-    @Value("${scene.num.threshold:10000}")
+    @Value("${scene.num.threshold:1000}")
     private int threshold;
-    @Value("${scene.num.prefix:V4-}")
+    @Value("${scene.num.prefix}")
     private String numPrefix;
     @Value("${scene.num.batchSize:100}")
     private int batchSize;
+    @Value("${main.url}")
+    private String mainUrl;
+
+    @Autowired
+    private DingTalkSendUtils dingTalkSendUtils;
 
     @Override
-    public String generateSceneNum(Integer cameraType){
+    public String generateSceneNum(Integer cameraType) throws Exception {
         // 从缓存中获取
         String sceneNum = redisUtil.lLeftPop(RedisKey.FDKANKAN_SCENE_NUMS);
         if(Objects.nonNull(sceneNum)){
             return addPrefix(sceneNum,cameraType);
         }
+        //为了防止场景量暴增导致定时任务来还不急处理,如果上面redis获取不到,需要调用一下生成场景码方法
+        log.warn("定时任务没有生成足够的场景码,此处实时调用批量生成场景码程序");
+        this.generateSceneNumHandler();
+        Thread.sleep(5000L);
+        // 从缓存中获取
+        sceneNum = redisUtil.lLeftPop(RedisKey.FDKANKAN_SCENE_NUMS);
+        if(Objects.isNull(sceneNum)){
+            String content = String.format(this.DINGTALK_MSG_PATTERN, mainUrl, "场景码穷尽告警", "场景计算获取场景码失败");
+            dingTalkSendUtils.sendActioncardMsgToDingRobot(content, "场景码穷尽告警");
+            throw new Exception("场景计算获取场景码失败");
+        }
+        return addPrefix(sceneNum,cameraType);
+    }
+
+    @Override
+    public void generateSceneNumHandler() {
+        boolean lock =  redisLockUtil.lock(RedisLockKey.LOCK_FDKANKAN_SCENE_NUMS, RedisKey.EXPIRE_TIME_30_MINUTE);
+        if(!lock){
+            return;
+        }
         // 分布式加锁
-        boolean lock =  redisLockUtil.lock(RedisLockKey.LOCK_FDKANKAN_SCENE_NUMS, RedisKey.EXPIRE_TIME_10_MINUTE);
-        if (lock) {
-            try {
-                log.info("开始加载场景码缓存");
-                List<String> nums = this.findSceneNum(cachePageSize);
-                if(CollectionUtils.isEmpty(nums)){
-                    batchCreateSceneNum(true);
-                    nums = this.findSceneNum(cachePageSize);
-                }else{
-                    CompletableFuture.runAsync(() -> batchCreateSceneNum(false));
-                }
+        try {
+            //检查mysql码池中是否有足够的未使用场景,不够时,需要创建一批
+            batchCreateSceneNum(false);
+
+            //检查redis中场景码是否少于指定缓存数量,少于时,需要从码池中获取
+            long redisCnt = redisUtil.lGetSize(RedisKey.FDKANKAN_SCENE_NUMS);
+            if(redisCnt >= cachePageSize){
+                return;
+            }
+            log.info("开始加载场景码缓存");
+            List<String> nums = this.findSceneNum(cachePageSize);
+            if(CollUtil.isEmpty(nums) || nums.size() < cachePageSize){
+                String content = String.format(this.DINGTALK_MSG_PATTERN, mainUrl, "场景码穷尽告警", "场景码表中未使用状态少于" + cachePageSize);
+                dingTalkSendUtils.sendActioncardMsgToDingRobot(content, "场景码穷尽告警");
+            }
+            if(CollUtil.isNotEmpty(nums)){
                 redisUtil.lRightPushAll(RedisKey.FDKANKAN_SCENE_NUMS, nums);
                 this.updateUsedStatus(nums);
-                log.info("场景码加载缓存完成");
-            } catch (Exception e) {
-                log.error("场景码加载缓存失败", e);
-            } finally {
-                redisLockUtil.unlockLua(RedisLockKey.LOCK_FDKANKAN_SCENE_NUMS);
             }
-        }else{
-            // 等待2秒加载缓存
-            try {
-                Thread.sleep(2000);
-            } catch (InterruptedException e) {
-                e.printStackTrace();
-            }
-        }
-        sceneNum = redisUtil.lLeftPop(RedisKey.FDKANKAN_SCENE_NUMS);
-        if(StrUtil.isEmpty(sceneNum)){
-            log.error("场景码加载失败");
-            throw new BusinessException(ErrorCode.FAILURE_CODE_5053);
+            log.info("场景码加载缓存完成");
+        } catch (Exception e) {
+            log.error("场景码加载缓存失败", e);
+        } finally {
+            redisLockUtil.unlockLua(RedisLockKey.LOCK_FDKANKAN_SCENE_NUMS);
         }
-        return addPrefix(sceneNum,cameraType);
     }
 
     private  static  String addPrefix( String num,Integer cameraType){
@@ -106,35 +132,26 @@ public class Scene3dNumServiceImpl extends ServiceImpl<IScene3dNumMapper, Scene3
 
     @Override
     public void batchCreateSceneNum(boolean force) {
-        String lockKey = String.format(RedisLockKey.LOCK_BATCH_CREATE_NUM);
-        boolean lock = redisLockUtil.lock(lockKey, RedisKey.EXPIRE_TIME_10_MINUTE);
-        if(!lock){
-            return;
-        }
-        try {
-            if (!force) {
-                long count = this.count(new LambdaQueryWrapper<Scene3dNum>().eq(Scene3dNum::getUsed, CommonStatus.NO.code()));
-                if (count > threshold) {
-                    return;
-                }
+        if (!force) {
+            long count = this.count(new LambdaQueryWrapper<Scene3dNum>().eq(Scene3dNum::getUsed, CommonStatus.NO.code()));
+            if (count > threshold) {
+                return;
             }
-            int batchCnt = threshold / batchSize + (threshold % batchSize > 0 ? 1 : 0);
-            for (int i = 0; i < batchCnt; i++){
-                Set<String> numSet = this.turnCreateSceneNum(batchSize);
-                List<Scene3dNum> scene3dNumList = numSet.parallelStream().map(num -> {
-                    Scene3dNum scene3dNum = new Scene3dNum();
-                    scene3dNum.setNum(num);
-                    return scene3dNum;
-                }).collect(Collectors.toList());
-                try{
-                    this.saveBatch(scene3dNumList);
-                }catch (Exception e){
-                    log.error("场景码插入异常!");
-                    e.printStackTrace();
-                }
+        }
+        int batchCnt = threshold / batchSize + (threshold % batchSize > 0 ? 1 : 0);//批次数
+        for (int i = 0; i < batchCnt; i++){//分批生成,每批次batchSize个
+            Set<String> numSet = this.turnCreateSceneNum(batchSize);
+            List<Scene3dNum> scene3dNumList = numSet.parallelStream().map(num -> {
+                Scene3dNum scene3dNum = new Scene3dNum();
+                scene3dNum.setCode(num);
+                return scene3dNum;
+            }).collect(Collectors.toList());
+            try{
+                this.saveBatch(scene3dNumList);
+            }catch (Exception e){
+                log.error("场景码插入异常!");
+                e.printStackTrace();
             }
-        }finally {
-            redisLockUtil.unlockLua(lockKey);
         }
     }
 

+ 3 - 3
src/main/resources/bootstrap-test.yml

@@ -2,9 +2,9 @@ spring:
   cloud:
     nacos:
       config:
-        server-addr: 172.20.1.63:8848
+        server-addr: 120.24.144.164:8848
         file-extension: yaml
-        namespace: 4dkankan-v4-prod
+        namespace: 4dkankan-v4-test
         extension-configs:
           - data-id: 4dkankan-center-modeling-control.yaml
             group: DEFAULT_GROUP
@@ -35,7 +35,7 @@ spring:
             refresh: true
       discovery:
         server-addr: ${spring.cloud.nacos.config.server-addr}
-        namespace: ${spring.cloud.nacos.config.namespace}
+        namespace: public