Prechádzať zdrojové kódy

feat : 数据推送错误日志定时删除

bilingfeng 9 mesiacov pred
rodič
commit
fdee13efcc

+ 28 - 0
game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/entity/CpPushErrorLog.java

@@ -23,6 +23,9 @@ public class CpPushErrorLog implements Serializable {
 
     private static final long serialVersionUID = 1L;
 
+    public final static Integer STATUS_VALID = 0;
+    public final static Integer STATUS_INVALID = 1;
+
     /**
      * id
      */
@@ -39,6 +42,26 @@ public class CpPushErrorLog implements Serializable {
      */
     private Long gameId;
 
+    /**
+     * 玩家应用唯一标识
+     */
+    private String openId;
+
+    /**
+     * 订单id
+     */
+    private String orderId;
+
+    /**
+     * 区服id
+     */
+    private String serverId;
+
+    /**
+     * 角色id
+     */
+    private String roleId;
+
     /**
      * 请求参数
      */
@@ -49,6 +72,11 @@ public class CpPushErrorLog implements Serializable {
      */
     private String errorMsg;
 
+    /**
+     * 有效状态, 0 : 有效, 1 : 无效,可删除
+     */
+    private Integer status;
+
     /**
      * 创建时间
      */

+ 1 - 1
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/SDKApplication.java

@@ -23,7 +23,7 @@ public class SDKApplication {
 
     public static void main(String[] args) {
         SpringApplication.run(SDKApplication.class, args);
-        System.out.println("赞象SDK服务启动成功 <回传判断兼容降档规则> ( ´・・)ノ(._.`) \n" +
+        System.out.println("赞象SDK服务启动成功 <数据推送错误日志定时删除> ( ´・・)ノ(._.`) \n" +
                 " ___________ _   __\n" +
                 "/  ___|  _  \\ | / /\n" +
                 "\\ `--.| | | | |/ / \n" +

+ 5 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/constant/RedisKeyConstant.java

@@ -81,4 +81,9 @@ public class RedisKeyConstant {
      * 回调判断锁
      */
     public static final String CALL_BACK_JUDGE_LOCK = RedisKeyConstant.REDIS_PREFIX + "call_back_judge_lock_";
+
+    /**
+     * CP推送数据错误日志删除锁
+     */
+    public static final String CP_PUSH_ERROR_LOG_LOCK = RedisKeyConstant.REDIS_PREFIX + "cp_push_error_log_lock";
 }

+ 9 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/ICpPushErrorLogService.java

@@ -20,4 +20,13 @@ public interface ICpPushErrorLogService extends IService<CpPushErrorLog> {
      * @param errorMsg       : 错误信息
      */
     void createLog(Long gameId, CpPushDataEnum cpPushDataEnum, Object param, String errorMsg);
+
+    /**
+     * CP推送数据错误日志更新
+     *
+     * @param gameId         : 游戏id
+     * @param cpPushDataEnum : 数据类型枚举
+     * @param param          : 参数
+     */
+    void errorLogUpdate(Long gameId, CpPushDataEnum cpPushDataEnum, Object param);
 }

+ 64 - 38
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/CpPushDataServiceImpl.java

@@ -33,6 +33,7 @@ import reactor.util.function.Tuple3;
 import reactor.util.function.Tuples;
 
 import java.time.LocalDateTime;
+import java.util.Base64;
 import java.util.Collections;
 import java.util.Map;
 import java.util.Objects;
@@ -135,6 +136,8 @@ public class CpPushDataServiceImpl implements ICpPushDataService {
             //下单
             kafkaService.eventTrack(KafkaEventTrackEnum.KAFKA_EVENT_TRACK_ORDER_PAY, JsonUtil.toString(order));
         }
+        //日志更新
+        cpPushErrorLogService.errorLogUpdate(game.getId(), CpPushDataEnum.CP_PUSH_DATA_ORDER, param);
         //构造返回
         return CpPushResultVO.builder().result(Boolean.TRUE).build();
     }
@@ -151,14 +154,12 @@ public class CpPushDataServiceImpl implements ICpPushDataService {
                     .eq(User::getOpenId, param.getOpenId())
                     .eq(User::getGameId, game.getId()));
             if (user == null) {
-                log.error("[订单推送]游戏玩家信息不存在, game : {}, param : {}", JsonUtil.toString(game), JsonUtil.toString(param));
                 throw new BaseException("[订单推送]玩家信息不存在");
             }
             //玩家信息
             GameUser gameUser = gameUserService.getOne(new LambdaQueryWrapper<GameUser>()
                     .eq(GameUser::getUserId, user.getId()));
             if (gameUser == null) {
-                log.error("[订单推送]游戏玩家信息不存在, game : {}, param : {}", JsonUtil.toString(game), JsonUtil.toString(param));
                 throw new BaseException("[订单推送]游戏玩家信息不存在");
             }
             //角色信息
@@ -167,7 +168,6 @@ public class CpPushDataServiceImpl implements ICpPushDataService {
                     .eq(GameUserRole::getUserId, user.getId())
                     .eq(GameUserRole::getRoleId, param.getRoleId()));
             if (gameUserRole == null) {
-                log.error("[订单推送]角色信息不存在, game : {}, param : {}", JsonUtil.toString(game), JsonUtil.toString(param));
                 throw new BaseException("[订单推送]角色信息不存在");
             }
             //构造订单
@@ -246,6 +246,8 @@ public class CpPushDataServiceImpl implements ICpPushDataService {
             //抛出异常
             throw new BaseException(e.getMessage());
         }
+        //日志更新
+        cpPushErrorLogService.errorLogUpdate(game.getId(), CpPushDataEnum.CP_PUSH_DATA_ACTIVE, param);
         //构造返回
         return CpPushResultVO.builder().result(Boolean.TRUE).build();
     }
@@ -254,6 +256,7 @@ public class CpPushDataServiceImpl implements ICpPushDataService {
     public CpPushResultVO pushServer(String gameAppId, CpPushServerParam param) {
         //查询游戏
         Game game = this.getGameByGameAppId(gameAppId);
+        boolean result;
         // 手动开启事务
         TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
         try {
@@ -274,19 +277,21 @@ public class CpPushDataServiceImpl implements ICpPushDataService {
                 gameServer.setUpdateTime(LocalDateTime.now());
             }
             //区服添加或者更新
-            boolean result = gameServerService.saveOrUpdate(gameServer);
-            // 提交事务
+            result = gameServerService.saveOrUpdate(gameServer);
+            //提交事务
             dataSourceTransactionManager.commit(transactionStatus);
-            //构造返回
-            return CpPushResultVO.builder().result(result).build();
         } catch (Exception e) {
-            // 回滚事务
+            //回滚事务
             dataSourceTransactionManager.rollback(transactionStatus);
             //保存错误日志
             cpPushErrorLogService.createLog(game.getId(), CpPushDataEnum.CP_PUSH_DATA_SERVER, param, e.getMessage());
             //抛出异常
             throw new BaseException(e.getMessage());
         }
+        //日志更新
+        cpPushErrorLogService.errorLogUpdate(game.getId(), CpPushDataEnum.CP_PUSH_DATA_SERVER, param);
+        //构造返回
+        return CpPushResultVO.builder().result(result).build();
     }
 
     private GameServer transform(Long superGameId, CpPushServerParam param) {
@@ -310,6 +315,7 @@ public class CpPushDataServiceImpl implements ICpPushDataService {
     public CpPushResultVO pushRole(String gameAppId, CpPushRoleParam param) {
         //查询游戏
         Game game = this.getGameByGameAppId(gameAppId);
+        boolean result;
         // 手动开启事务
         TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
         try {
@@ -318,7 +324,6 @@ public class CpPushDataServiceImpl implements ICpPushDataService {
                     .eq(User::getGameId, game.getId())
                     .eq(User::getOpenId, param.getOpenId()));
             if (user == null) {
-                log.error("[角色推送]玩家信息不存在, game : {}, param : {}", JsonUtil.toString(game), JsonUtil.toString(param));
                 throw new BaseException("[角色推送]玩家信息不存在");
             }
             //查询玩家角色信息
@@ -326,7 +331,6 @@ public class CpPushDataServiceImpl implements ICpPushDataService {
                     .eq(GameUserRole::getUserId, user.getId())
                     .eq(GameUserRole::getGameId, user.getGameId())
                     .eq(GameUserRole::getRoleId, param.getRoleId()));
-            boolean result;
             if (gameUserRole == null) {
                 result = this.gameRoleCreate(param, user);
             } else {
@@ -334,8 +338,6 @@ public class CpPushDataServiceImpl implements ICpPushDataService {
             }
             // 提交事务
             dataSourceTransactionManager.commit(transactionStatus);
-            //构造返回
-            return CpPushResultVO.builder().result(result).build();
         } catch (Exception e) {
             // 回滚事务
             dataSourceTransactionManager.rollback(transactionStatus);
@@ -344,6 +346,10 @@ public class CpPushDataServiceImpl implements ICpPushDataService {
             //抛出异常
             throw new BaseException(e.getMessage());
         }
+        //日志更新
+        cpPushErrorLogService.errorLogUpdate(game.getId(), CpPushDataEnum.CP_PUSH_DATA_ROLE, param);
+        //构造返回
+        return CpPushResultVO.builder().result(result).build();
     }
 
     private boolean gameRoleCreate(CpPushRoleParam param, User user) {
@@ -352,7 +358,6 @@ public class CpPushDataServiceImpl implements ICpPushDataService {
                 .eq(GameUser::getGameId, user.getGameId())
                 .eq(GameUser::getUserId, user.getId()));
         if (gameUser == null) {
-            log.error("[角色推送]游戏玩家信息不存在, param : {}, user : {}", JsonUtil.toString(param), JsonUtil.toString(user));
             throw new BaseException("[角色推送]游戏玩家信息不存在");
         }
         //上锁
@@ -436,26 +441,23 @@ public class CpPushDataServiceImpl implements ICpPushDataService {
     public CpPushUserVO pushUser(String gameAppId, CpPushUserParam param) {
         //查询游戏
         Game game = this.getGameByGameAppId(gameAppId);
+        //结果信息
+        CpPushUserVO cpPushUserVO;
         // 手动开启事务
         TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
         try {
-            //渠道参数判断
-            String channel = param.getChannel();
-            Tuple2<Boolean, Boolean> jsonAndEmpty = this.isJsonAndEmpty(channel);
             //中间数据
             UserData userData = UserData.builder().gameId(game.getId()).channel(param.getChannel()).ip(param.getIp()).ua(param.getUa()).build();
             //根据openId查询用户
             User user = userService.getOne(new LambdaQueryWrapper<User>()
                     .eq(User::getGameId, game.getId())
                     .eq(User::getOpenId, param.getOpenId()));
-            //结果信息
-            CpPushUserVO cpPushUserVO;
             //玩家信息不存在
             if (user == null) {
-                cpPushUserVO = this.createUser(game, userData, param, jsonAndEmpty);
+                cpPushUserVO = this.createUser(game, userData, param);
             } else {
                 //玩家信息更新
-                Map<String, String> channelMap = this.updateUser(user, param, game, userData, jsonAndEmpty);
+                Map<String, String> channelMap = this.updateUser(user, param, game, userData);
                 cpPushUserVO = CpPushUserVO.builder().userId(user.getId())
                         .sdkUser(!Objects.equals(user.getAgentId(), Agent.DEFAULT_AGENT))
                         .channel(JsonUtil.toString(channelMap))
@@ -463,8 +465,6 @@ public class CpPushDataServiceImpl implements ICpPushDataService {
             }
             // 提交事务
             dataSourceTransactionManager.commit(transactionStatus);
-            //返回结果
-            return cpPushUserVO;
         } catch (Exception e) {
             // 回滚事务
             dataSourceTransactionManager.rollback(transactionStatus);
@@ -473,9 +473,13 @@ public class CpPushDataServiceImpl implements ICpPushDataService {
             //抛出异常
             throw new BaseException(e.getMessage());
         }
+        //日志更新
+        cpPushErrorLogService.errorLogUpdate(game.getId(), CpPushDataEnum.CP_PUSH_DATA_USER, param);
+        //返回结果
+        return cpPushUserVO;
     }
 
-    private CpPushUserVO createUser(Game game, UserData userData, CpPushUserParam param, Tuple2<Boolean, Boolean> jsonAndEmpty) {
+    private CpPushUserVO createUser(Game game, UserData userData, CpPushUserParam param) {
         //游戏id
         Long gameId = game.getId();
         //线程锁Key
@@ -496,10 +500,10 @@ public class CpPushDataServiceImpl implements ICpPushDataService {
                         .eq(User::getGameId, gameId)
                         .eq(User::getOpenId, param.getShareOpenId())
                         .last("limit 1"));
-                user = this.transform(gameId, shareUser.getAgentId(), shareUser, param);
+                user = this.transform(gameId, shareUser, param);
             } else {
-                Tuple2<Long, Map<String, String>> tuple2 = this.getUserAgentChannel(game, userData, jsonAndEmpty);
-                user = this.transform(gameId, tuple2.getT1(), null, param);
+                Tuple2<Long, Map<String, String>> tuple2 = this.getUserAgentChannel(game, userData);
+                user = this.transform(gameId, tuple2, param);
                 channelMap = tuple2.getT2();
             }
             userService.save(user);
@@ -530,19 +534,15 @@ public class CpPushDataServiceImpl implements ICpPushDataService {
         }
     }
 
-    private Map<String, String> updateUser(User user, CpPushUserParam param, Game game, UserData userData, Tuple2<Boolean, Boolean> jsonAndEmpty) {
+    private Map<String, String> updateUser(User user, CpPushUserParam param, Game game, UserData userData) {
         //活跃间隔时长
         long inactiveDay = 15L;
         //判定不活跃时长是否达到限制
         if (param.getActiveTime().plusDays(inactiveDay).isAfter(LocalDateTime.now())) {
             return Collections.emptyMap();
         }
-        //如果没有携带参数, 不判定重新买量
-        if (!param.getChannel().contains("clue_token")) {
-            return Collections.emptyMap();
-        }
         //渠道id, 链接参数
-        Tuple2<Long, Map<String, String>> tuple2 = this.getUserAgentChannel(game, userData, jsonAndEmpty);
+        Tuple2<Long, Map<String, String>> tuple2 = this.getUserAgentChannel(game, userData);
         //查询渠道
         Agent agent = agentService.getById(tuple2.getT1());
         if (agent == null) {
@@ -563,7 +563,14 @@ public class CpPushDataServiceImpl implements ICpPushDataService {
         return tuple2.getT2();
     }
 
-    private Tuple2<Long, Map<String, String>> getUserAgentChannel(Game game, UserData userData, Tuple2<Boolean, Boolean> jsonAndEmpty) {
+    private Tuple2<Long, Map<String, String>> getUserAgentChannel(Game game, UserData userData) {
+        //解析渠道信息
+        String channel = new String(Base64.getDecoder().decode(userData.getChannel()));
+        //没有携带渠道标识, 无法解析渠道信息, 判定为自然量
+        if (!channel.contains("agentKey") || !channel.contains("state")) {
+            return Tuples.of(0L, Collections.emptyMap());
+        }
+        Tuple2<Boolean, Boolean> jsonAndEmpty = this.isJsonAndEmpty(channel);
         //channel渠道信息非json格式, 或者是空json
         if (!jsonAndEmpty.getT1() || jsonAndEmpty.getT2()) {
             //返回自然量渠道
@@ -575,12 +582,32 @@ public class CpPushDataServiceImpl implements ICpPushDataService {
         return Tuples.of(tuple3.getT1(), tuple3.getT2());
     }
 
-    private User transform(Long gameId, Long agentId, User shareUser, CpPushUserParam param) {
+    private User transform(Long gameId, User shareUser, CpPushUserParam param) {
+        return User.builder()
+                .openId(param.getOpenId())
+                .regAgentId(shareUser.getRegAgentId())
+                .agentId(shareUser.getAgentId())
+                .channel(shareUser.getChannel())
+                .gameId(gameId)
+                .username(param.getOpenId())
+                .nickname(RegisterUtil.randomNickName(param.getOpenId()))
+                .deviceType(DeviceTypeEnum.DEVICE_TYPE_MINI_APP.getDeviceType())
+                .status(BanStatusEnum.NORMAL_STATUS.getStatus())
+                .authentication(0)
+                .createTime(param.getRegTime())
+                .updateTime(LocalDateTime.now())
+                .deviceSystem(param.getOs())
+                .ip(param.getIp())
+                .shareUserId(shareUser.getId())
+                .build();
+    }
+
+    private User transform(Long gameId, Tuple2<Long, Map<String, String>> tuple2, CpPushUserParam param) {
         return User.builder()
                 .openId(param.getOpenId())
-                .regAgentId(agentId)
-                .agentId(agentId)
-                .channel(param.getChannel())
+                .regAgentId(tuple2.getT1())
+                .agentId(tuple2.getT1())
+                .channel(JsonUtil.toString(tuple2))
                 .gameId(gameId)
                 .username(param.getOpenId())
                 .nickname(RegisterUtil.randomNickName(param.getOpenId()))
@@ -591,7 +618,6 @@ public class CpPushDataServiceImpl implements ICpPushDataService {
                 .updateTime(LocalDateTime.now())
                 .deviceSystem(param.getOs())
                 .ip(param.getIp())
-                .shareUserId(shareUser == null ? null : shareUser.getId())
                 .build();
     }
 

+ 25 - 1
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/CpPushErrorLogServiceImpl.java

@@ -1,5 +1,6 @@
 package com.zanxiang.game.module.sdk.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.zanxiang.game.module.mybatis.entity.CpPushErrorLog;
 import com.zanxiang.game.module.mybatis.mapper.CpPushErrorLogMapper;
@@ -7,9 +8,11 @@ import com.zanxiang.game.module.sdk.enums.CpPushDataEnum;
 import com.zanxiang.game.module.sdk.service.ICpPushErrorLogService;
 import com.zanxiang.module.util.JsonUtil;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.logging.log4j.util.Strings;
 import org.springframework.stereotype.Service;
 
 import java.time.LocalDateTime;
+import java.util.Map;
 
 /**
  * @author : lingfeng
@@ -22,12 +25,33 @@ public class CpPushErrorLogServiceImpl extends ServiceImpl<CpPushErrorLogMapper,
 
     @Override
     public void createLog(Long gameId, CpPushDataEnum cpPushDataEnum, Object param, String errorMsg) {
+        String paramJsonStr = JsonUtil.toString(param);
+        Map<String, String> paramMap = JsonUtil.toMap(paramJsonStr, Map.class, String.class);
         super.save(CpPushErrorLog.builder()
                 .dataType(cpPushDataEnum.getValue())
                 .gameId(gameId)
-                .param(JsonUtil.toString(param))
+                .openId(paramMap.get("openId"))
+                .orderId(paramMap.get("orderId"))
+                .serverId(paramMap.get("serverId"))
+                .roleId(paramMap.get("roleId"))
+                .param(paramJsonStr)
                 .errorMsg(errorMsg)
+                .status(CpPushErrorLog.STATUS_VALID)
                 .createTime(LocalDateTime.now())
                 .build());
     }
+
+    @Override
+    public void errorLogUpdate(Long gameId, CpPushDataEnum cpPushDataEnum, Object param) {
+        Map<String, String> paramMap = JsonUtil.toMap(JsonUtil.toString(param), Map.class, String.class);
+        super.update(new LambdaUpdateWrapper<CpPushErrorLog>()
+                .set(CpPushErrorLog::getStatus, CpPushErrorLog.STATUS_INVALID)
+                .eq(CpPushErrorLog::getGameId, gameId)
+                .eq(CpPushErrorLog::getDataType, cpPushDataEnum.getValue())
+                .eq(Strings.isNotBlank(paramMap.get("openId")), CpPushErrorLog::getOpenId, paramMap.get("openId"))
+                .eq(Strings.isNotBlank(paramMap.get("orderId")), CpPushErrorLog::getOrderId, paramMap.get("orderId"))
+                .eq(Strings.isNotBlank(paramMap.get("serverId")), CpPushErrorLog::getServerId, paramMap.get("serverId"))
+                .eq(Strings.isNotBlank(paramMap.get("roleId")), CpPushErrorLog::getRoleId, paramMap.get("roleId"))
+        );
+    }
 }

+ 47 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/task/CpPushDataTask.java

@@ -0,0 +1,47 @@
+package com.zanxiang.game.module.sdk.task;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.zanxiang.game.module.mybatis.entity.CpPushErrorLog;
+import com.zanxiang.game.module.sdk.constant.RedisKeyConstant;
+import com.zanxiang.game.module.sdk.service.ICpPushErrorLogService;
+import com.zanxiang.module.redis.service.IDistributedLockComponent;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-07-02
+ * @description : CP推送数据
+ */
+@Slf4j
+@Component
+@RefreshScope
+public class CpPushDataTask {
+
+    @Autowired
+    private ICpPushErrorLogService cpPushErrorLogService;
+
+    @Autowired
+    private IDistributedLockComponent distributedLockComponent;
+
+    /**
+     * 无效错误日志定时删除, 1小时执行一次
+     */
+    @Scheduled(cron = "0 0 0/1 * * ?")
+    public void cpPushErrorLogDel() {
+        //上锁
+        if (!distributedLockComponent.doLock(RedisKeyConstant.CP_PUSH_ERROR_LOG_LOCK, 0L, 30L, TimeUnit.MINUTES)) {
+            return;
+        }
+        log.error("[CP推送数据]无效错误日志定时删除");
+        //删除无效的日志
+        cpPushErrorLogService.remove(new LambdaQueryWrapper<CpPushErrorLog>()
+                .eq(CpPushErrorLog::getStatus, CpPushErrorLog.STATUS_INVALID)
+        );
+    }
+}