Scene3dNumServiceImpl.java 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. package com.fdkankan.contro.service.impl;
  2. import cn.hutool.core.collection.CollUtil;
  3. import cn.hutool.core.util.StrUtil;
  4. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  5. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  6. import com.fdkankan.common.constant.CommonStatus;
  7. import com.fdkankan.common.constant.ErrorCode;
  8. import com.fdkankan.common.exception.BusinessException;
  9. import com.fdkankan.common.util.RandomUtil;
  10. import com.fdkankan.contro.entity.CameraType;
  11. import com.fdkankan.contro.entity.Scene3dNum;
  12. import com.fdkankan.contro.enums.CameraTypeEnum;
  13. import com.fdkankan.contro.mapper.IScene3dNumMapper;
  14. import com.fdkankan.contro.service.ICameraTypeService;
  15. import com.fdkankan.contro.service.IScene3dNumService;
  16. //import com.fdkankan.dingtalk.DingTalkSendUtils;
  17. import com.fdkankan.redis.constant.RedisKey;
  18. import com.fdkankan.redis.constant.RedisLockKey;
  19. import com.fdkankan.redis.util.RedisLockUtil;
  20. import com.fdkankan.redis.util.RedisUtil;
  21. import lombok.extern.slf4j.Slf4j;
  22. import org.springframework.beans.factory.annotation.Autowired;
  23. import org.springframework.beans.factory.annotation.Value;
  24. import org.springframework.cloud.context.config.annotation.RefreshScope;
  25. import org.springframework.stereotype.Service;
  26. import org.springframework.util.CollectionUtils;
  27. import java.util.HashSet;
  28. import java.util.List;
  29. import java.util.Objects;
  30. import java.util.Set;
  31. import java.util.concurrent.CompletableFuture;
  32. import java.util.stream.Collectors;
  33. /**
  34. * <p>
  35. * 八目场景编码表 服务实现类
  36. * </p>
  37. *
  38. * @author dengsixing
  39. * @since 2021-12-23
  40. */
  41. @RefreshScope
  42. @Slf4j
  43. @Service
  44. public class Scene3dNumServiceImpl extends ServiceImpl<IScene3dNumMapper, Scene3dNum> implements IScene3dNumService {
  45. public static final String DINGTALK_MSG_PATTERN =
  46. "**环境**: %s\n\n" +
  47. "**标题**: %s\n\n" +
  48. "**告警信息**: %s\n\n";
  49. @Autowired
  50. private RedisUtil redisUtil;
  51. @Autowired
  52. private RedisLockUtil redisLockUtil;
  53. @Value("${scene.num.cachePageSize:500}")
  54. private int cachePageSize;
  55. @Value("${scene.num.threshold:1000}")
  56. private int threshold;
  57. @Value("${scene.num.prefix}")
  58. private String numPrefix;
  59. @Value("${scene.num.batchSize:100}")
  60. private int batchSize;
  61. @Value("${main.url}")
  62. private String mainUrl;
  63. // @Autowired
  64. // private DingTalkSendUtils dingTalkSendUtils;
  65. @Autowired
  66. private ICameraTypeService cameraTypeService;
  67. @Override
  68. public String generateSceneNum(Integer cameraType) throws Exception {
  69. // 从缓存中获取
  70. String sceneNum = redisUtil.lLeftPop(RedisKey.FDKANKAN_SCENE_NUMS);
  71. if(Objects.nonNull(sceneNum)){
  72. return addPrefix(sceneNum,cameraType);
  73. }
  74. //为了防止场景量暴增导致定时任务来还不急处理,如果上面redis获取不到,需要调用一下生成场景码方法
  75. log.warn("定时任务没有生成足够的场景码,此处实时调用批量生成场景码程序");
  76. this.generateSceneNumHandler();
  77. Thread.sleep(5000L);
  78. // 从缓存中获取
  79. sceneNum = redisUtil.lLeftPop(RedisKey.FDKANKAN_SCENE_NUMS);
  80. if(Objects.isNull(sceneNum)){
  81. String content = String.format(this.DINGTALK_MSG_PATTERN, mainUrl, "场景码穷尽告警", "场景计算获取场景码失败");
  82. // dingTalkSendUtils.sendActioncardMsgToDingRobot(content, "场景码穷尽告警");
  83. throw new Exception("场景计算获取场景码失败");
  84. }
  85. return addPrefix(sceneNum,cameraType);
  86. }
  87. @Override
  88. public void generateSceneNumHandler() {
  89. boolean lock = redisLockUtil.lock(RedisLockKey.LOCK_FDKANKAN_SCENE_NUMS, RedisKey.EXPIRE_TIME_30_MINUTE);
  90. if(!lock){
  91. return;
  92. }
  93. // 分布式加锁
  94. try {
  95. //检查mysql码池中是否有足够的未使用场景,不够时,需要创建一批
  96. batchCreateSceneNum(false);
  97. //检查redis中场景码是否少于指定缓存数量,少于时,需要从码池中获取
  98. long redisCnt = redisUtil.lGetSize(RedisKey.FDKANKAN_SCENE_NUMS);
  99. if(redisCnt >= cachePageSize){
  100. return;
  101. }
  102. log.info("开始加载场景码缓存");
  103. List<String> nums = this.findSceneNum(cachePageSize);
  104. if(CollUtil.isEmpty(nums) || nums.size() < cachePageSize){
  105. String content = String.format(this.DINGTALK_MSG_PATTERN, mainUrl, "场景码穷尽告警", "场景码表中未使用状态少于" + cachePageSize);
  106. // dingTalkSendUtils.sendActioncardMsgToDingRobot(content, "场景码穷尽告警");
  107. }
  108. if(CollUtil.isNotEmpty(nums)){
  109. redisUtil.lRightPushAll(RedisKey.FDKANKAN_SCENE_NUMS, nums);
  110. this.updateUsedStatus(nums);
  111. }
  112. log.info("场景码加载缓存完成");
  113. } catch (Exception e) {
  114. log.error("场景码加载缓存失败", e);
  115. } finally {
  116. redisLockUtil.unlockLua(RedisLockKey.LOCK_FDKANKAN_SCENE_NUMS);
  117. }
  118. }
  119. private String addPrefix(String num,Integer camType){
  120. if(camType == null){
  121. return num;
  122. }
  123. CameraType cameraType = cameraTypeService.getByCamType(camType);
  124. if(Objects.isNull(cameraType)){
  125. return num;
  126. }
  127. return cameraType.getScenePrefix() + num;
  128. }
  129. @Override
  130. public void batchCreateSceneNum(boolean force) {
  131. if (!force) {
  132. long count = this.count(new LambdaQueryWrapper<Scene3dNum>().eq(Scene3dNum::getUsed, CommonStatus.NO.code()));
  133. if (count > threshold) {
  134. return;
  135. }
  136. }
  137. int batchCnt = threshold / batchSize + (threshold % batchSize > 0 ? 1 : 0);//批次数
  138. for (int i = 0; i < batchCnt; i++){//分批生成,每批次batchSize个
  139. Set<String> numSet = this.turnCreateSceneNum(batchSize);
  140. List<Scene3dNum> scene3dNumList = numSet.parallelStream().map(num -> {
  141. Scene3dNum scene3dNum = new Scene3dNum();
  142. scene3dNum.setCode(num);
  143. return scene3dNum;
  144. }).collect(Collectors.toList());
  145. try{
  146. this.saveBatch(scene3dNumList);
  147. }catch (Exception e){
  148. log.error("场景码插入异常!");
  149. e.printStackTrace();
  150. }
  151. }
  152. }
  153. private Set<String> turnCreateSceneNum(int cnt){
  154. Set<String> numSet = new HashSet<>();
  155. for(int i = 0; i < cnt; i++){
  156. numSet.add(numPrefix + RandomUtil.generateShortUuid());
  157. }
  158. return numSet;
  159. }
  160. @Override
  161. public List<String> findSceneNum(int pageSize) {
  162. return baseMapper.findSceneNum(pageSize);
  163. }
  164. @Override
  165. public void updateUsedStatus(List<String> nums) {
  166. baseMapper.updateUsedStatus(nums);
  167. }
  168. }