Просмотр исходного кода

商品库任务 调整通知消息,调整频控

zhaotx 9 месяцев назад
Родитель
Сommit
85ba7b8bb4

+ 115 - 22
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/data/service/impl/BytedanceProductUpdateServiceImpl.java

@@ -49,6 +49,32 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
     //商品上传结果通知群
     public static final String HOOK_URL = "https://open.feishu.cn/open-apis/bot/v2/hook/92e2445e-76df-44fb-8f61-f55ac94f49bd";
 
+    // 内部错误记录类:包含报错信息、剧目ID、商品库ID
+    private static class ErrorRecord {
+        String message;
+        String albumId; // 剧目ID
+        String platformId; // 商品库ID
+
+        public ErrorRecord(String message, String albumId, String platformId) {
+            this.message = message;
+            this.albumId = albumId;
+            this.platformId = platformId;
+        }
+
+        public String getMessage() { return message; }
+        public String getAlbumId() { return albumId; }
+        public String getPlatformId() { return platformId; }
+
+        @Override
+        public String toString() {
+            return "ErrorRecord{" +
+                    "message='" + message + '\'' +
+                    ", albumId='" + albumId + '\'' +
+                    ", platformId='" + platformId + '\'' +
+                    '}';
+        }
+    }
+
     public String runPlatform(String platformId) throws IOException {
         List<AigcProductPlatform> platform = bytedanceProductUpdateMapper.getPlatformList(null, platformId);
         if (platform.isEmpty()){
@@ -70,7 +96,7 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
     }
 
     private void runMiniProgram(String platformId) throws IOException {
-        Set<String> errors = new HashSet<>();
+        Set<ErrorRecord> errors = new HashSet<>();
         log.info("付费商品库更新中...");
         List<AigcProductPlatform> iapPlatformList = bytedanceProductUpdateMapper.getPlatformList("IAP", platformId); //商品库列表
         if (!iapPlatformList.isEmpty()){
@@ -99,11 +125,44 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
         }
         log.info("免费商品库更新完成");
 
-        errors.removeIf(s -> s.contains("剧目不可用"));
+        // 过滤掉包含“剧目不可用”的错误
+        errors.removeIf(er -> er.getMessage() != null && er.getMessage().contains("剧目不可用"));
         if (!Check.isNull(errors)){
             List<String> info = new ArrayList<>();
             info.add("商品上传报错通知");
-            info.addAll(errors);
+
+            // 合并相同剧目ID和报错信息的数据
+            Map<String, Set<String>> grouped = new LinkedHashMap<>(); // key -> set of platformIds
+            Map<String, String> keyToAlbum = new HashMap<>(); // key -> albumId
+            for (ErrorRecord er : errors){
+                String albumKey = er.getAlbumId() == null ? "" : er.getAlbumId();
+                String key = albumKey + "||" + er.getMessage();
+                grouped.computeIfAbsent(key, k -> new LinkedHashSet<>());
+                if (er.getPlatformId() != null){
+                    grouped.get(key).add(er.getPlatformId());
+                }
+                keyToAlbum.putIfAbsent(key, albumKey);
+            }
+
+            for (Map.Entry<String, Set<String>> e : grouped.entrySet()){
+                String key = e.getKey();
+                String[] parts = key.split("\\|\\|");
+                String message = parts.length>1 ? parts[1] : parts[0];
+                String albumId = keyToAlbum.get(key);
+                Set<String> platformIds = e.getValue();
+                StringBuilder sb = new StringBuilder();
+                sb.append(message);
+                if (StringUtils.isNotEmpty(albumId)){
+                    sb.append(",剧目ID: ").append(albumId);
+                }
+                if (platformIds != null && !platformIds.isEmpty()){
+                    if (platformIds.size() < 5){
+                        sb.append(",商品库ID: ").append(StringUtils.join(platformIds, ","));
+                    }
+                }
+                info.add(sb.toString());
+            }
+
             FeishuRobotUtil.sendTextToWebhook(StringUtils.join(info, "\n"), HOOK_URL);
         }
     }
@@ -114,7 +173,7 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
     }
 
     private void runDysDistribute(String platformId) throws IOException {
-        Set<String> errors = new HashSet<>();
+        Set<ErrorRecord> errors = new HashSet<>();
         List<AigcProductPlatform> iaaPlatformList = bytedanceProductUpdateMapper.getDysIaaPlatformList(platformId); //商品库列表
         if (iaaPlatformList.isEmpty()){
             return;
@@ -138,16 +197,49 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
         runDysProductTask(iaaPlatformList, iaaVideos, new HashMap<>(), errors, BusinessType.IAA);
         System.out.println("端原生分销商品库更新完成");
 
-        errors.removeIf(s -> s.contains("剧目不可用"));
+        // 过滤掉包含“剧目不可用”的错误
+        errors.removeIf(er -> er.getMessage() != null && er.getMessage().contains("剧目不可用"));
         if (!Check.isNull(errors)){
             List<String> info = new ArrayList<>();
             info.add("端原生分销商品上传报错通知");
-            info.addAll(errors);
+
+            // 合并相同剧目ID和报错信息的数据
+            Map<String, Set<String>> grouped = new LinkedHashMap<>(); // key -> set of platformIds
+            Map<String, String> keyToAlbum = new HashMap<>(); // key -> albumId
+            for (ErrorRecord er : errors){
+                String albumKey = er.getAlbumId() == null ? "" : er.getAlbumId();
+                String key = albumKey + "||" + er.getMessage();
+                grouped.computeIfAbsent(key, k -> new LinkedHashSet<>());
+                if (er.getPlatformId() != null){
+                    grouped.get(key).add(er.getPlatformId());
+                }
+                keyToAlbum.putIfAbsent(key, albumKey);
+            }
+
+            for (Map.Entry<String, Set<String>> e : grouped.entrySet()){
+                String key = e.getKey();
+                String[] parts = key.split("\\\\|\\\\|");
+                String message = parts.length>1 ? parts[1] : parts[0];
+                String albumId = keyToAlbum.get(key);
+                Set<String> platformIds = e.getValue();
+                StringBuilder sb = new StringBuilder();
+                sb.append(message);
+                if (StringUtils.isNotEmpty(albumId)){
+                    sb.append(",剧目ID: ").append(albumId);
+                }
+                if (platformIds != null && !platformIds.isEmpty()){
+                    if (platformIds.size() < 5){
+                        sb.append(",商品库ID: ").append(StringUtils.join(platformIds, ","));
+                    }
+                }
+                info.add(sb.toString());
+            }
+
             FeishuRobotUtil.sendTextToWebhook(StringUtils.join(info, "\n"), HOOK_URL);
         }
     }
 
-    private void runMpProductTask(List<AigcProductPlatform> platformList, List<AigcProductAlbum> albums, Map<String, JSONObject> productTypeMap, Set<String> errors, BusinessType businessType) throws IOException {
+    private void runMpProductTask(List<AigcProductPlatform> platformList, List<AigcProductAlbum> albums, Map<String, JSONObject> productTypeMap, Set<ErrorRecord> errors, BusinessType businessType) throws IOException {
         for (AigcProductPlatform platform : platformList){
             // 拉取已上传剧目,对比,得到未上传剧目列表
             List<AigcProductAlbum> hasUploadProductList = hasUploadProductList(platform);
@@ -163,7 +255,7 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
             }
             //获取未上传剧目的推广链接
             List<AigcProductAlbum> douyinUploadList = toUpload.stream().filter(o -> Objects.equals(o.getPlatformType(), "1")).collect(Collectors.toList());
-            Map<String, String> albumIdToLinkMap = getBytedancePlayletPromoteLink(platform.getMiniAppAdvertiserId(), platform.getAccessToken(), platform.getMiniInstanceId(), douyinUploadList, errors);
+            Map<String, String> albumIdToLinkMap = getBytedancePlayletPromoteLink(platform.getMiniAppAdvertiserId(), platform.getAccessToken(), platform.getMiniInstanceId(), douyinUploadList, errors, platform.getPlatformId());
             //未上传剧目:对比平台类型;确定商品分类;获取推广链接
             for (AigcProductAlbum album : toUpload){
                 if (!Objects.equals(album.getPlatformType(), String.valueOf(platform.getPlatformType()))){
@@ -189,7 +281,7 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
         }
     }
 
-    private void runDysProductTask(List<AigcProductPlatform> platformList, List<AigcProductAlbum> albums, Map<String, JSONObject> productTypeMap, Set<String> errors, BusinessType businessType) throws IOException {
+    private void runDysProductTask(List<AigcProductPlatform> platformList, List<AigcProductAlbum> albums, Map<String, JSONObject> productTypeMap, Set<ErrorRecord> errors, BusinessType businessType) throws IOException {
         for (AigcProductPlatform platform : platformList){
             // 拉取已上传剧目,对比,得到未上传剧目列表
             List<AigcProductAlbum> hasUploadAlbums = hasUploadProductList(platform);
@@ -405,7 +497,7 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
     }
 
     private void uploadProduct(AigcProductPlatform platform, AigcProductAlbum album,
-                                  String schemaLink, Set<String> errorBlanket, JSONObject productType,
+                                  String schemaLink, Set<ErrorRecord> errorBlanket, JSONObject productType,
                               BusinessType businessType){
         String url;
         if (StringUtils.isEmpty(album.getAlbumId())){
@@ -490,20 +582,20 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
         String res = HttpUtils.httpPostRequest(url, request, headers);
         if (res == null || res.isEmpty()){
             String payName = businessType==BusinessType.IAP?"付费":"免费";
-            errorBlanket.add("上传"+payName+"商品失败,msg: 请求失败或无响应, 关联剧目: " + album.getName());
+            errorBlanket.add(new ErrorRecord("上传"+payName+"商品失败,msg: 请求失败或无响应, 关联剧目: " + album.getName(), album.getAlbumId(), platform.getPlatformId()));
         } else {
             JSONObject btRes = JSONObject.parseObject(res);
             int code = btRes.getIntValue("code");
             if (code != 0){
                 String errorMessage = btRes.getString("message");
                 String payName = businessType==BusinessType.IAP?"付费":"免费";
-                errorBlanket.add("上传"+payName+"商品失败,code: [" + code + "], msg: [" + errorMessage +"], 关联剧目: " + album.getName());
+                errorBlanket.add(new ErrorRecord("上传"+payName+"商品失败,code: [" + code + "], msg: [" + errorMessage +"], 关联剧目: " + album.getName(), album.getAlbumId(), platform.getPlatformId()));
             }
         }
 
     }
 
-    private Map<String, String> getBytedancePlayletPromoteLink(String advertiserId, String accessToken, String instanceId, List<AigcProductAlbum> requests, Set<String> errorBlanket){
+    private Map<String, String> getBytedancePlayletPromoteLink(String advertiserId, String accessToken, String instanceId, List<AigcProductAlbum> requests, Set<ErrorRecord> errorBlanket, String platformId){
         List<String> reqAlbumIds = requests.stream()
                 .map(obj -> obj.getAlbumId())
                 .collect(Collectors.toList());
@@ -518,7 +610,7 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
      * @return map key: album_id, value: 对应的字节小程序推广链接,sslocal开头
      */
         for (int page=1; page<=20; page++){
-            JSONArray playletDetailInfo = getPlayletDetail(advertiserId, accessToken, instanceId, errorBlanket,page);
+            JSONArray playletDetailInfo = getPlayletDetail(advertiserId, accessToken, instanceId, errorBlanket, page, platformId);
             if (playletDetailInfo == null || playletDetailInfo.isEmpty()){
                 break;
             }
@@ -585,7 +677,7 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
             }
 
             if (rr == null || rr.isEmpty()){
-                errorBlanket.add("创建字节小程序推广链接失败, 广告账号ID:" + advertiserId + ", 小程序资产ID:" + instanceId);
+                errorBlanket.add(new ErrorRecord("创建字节小程序推广链接失败, 广告账号ID:" + advertiserId + ", 小程序资产ID:" + instanceId, obj.getAlbumId(), platformId));
                 System.out.println("创建字节小程序推广链接失败");
                 return res;
             }else {
@@ -594,13 +686,13 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
                 if (code != 0) {
                     String message = jsonObject.getString("message");
                     if (message.contains("资产非审核成功")){
-                        errorBlanket.add("字节小程序"+instanceId+"未通过审核,等待下次再试");
+                        errorBlanket.add(new ErrorRecord("字节小程序"+instanceId+"未通过审核,等待下次再试", obj.getAlbumId(), platformId));
                         break;
                     }else if (message.contains("请求频率超限")){
-                        errorBlanket.add("广告账号"+advertiserId+"请求频率超限");
+                        errorBlanket.add(new ErrorRecord("广告账号"+advertiserId+"请求频率超限", obj.getAlbumId(), platformId));
                         continue;
                     } else {
-                        errorBlanket.add("创建字节小程序推广链接失败,code: " + code + ", msg: " + jsonObject.getString("message") + ", 广告账号ID:" + advertiserId + ", 小程序资产ID:" + instanceId);
+                        errorBlanket.add(new ErrorRecord("创建字节小程序推广链接失败,code: " + code + ", msg: " + jsonObject.getString("message") + ", 广告账号ID:" + advertiserId + ", 小程序资产ID:" + instanceId, obj.getAlbumId(), platformId));
                         System.out.println("创建字节小程序推广链接失败,code: " + code + ", msg: " + jsonObject.getString("message"));
                         continue;
                     }
@@ -612,7 +704,7 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
         }
         int maxPage = unfound.size() / 100 + 1;
         for (int p = 0; p < maxPage; p++) {
-            JSONArray newPlayletDetailInfo = getPlayletDetail(advertiserId, accessToken, instanceId, errorBlanket,p+1);
+            JSONArray newPlayletDetailInfo = getPlayletDetail(advertiserId, accessToken, instanceId, errorBlanket, p+1, platformId);
             if (newPlayletDetailInfo == null || newPlayletDetailInfo.isEmpty()){
                 break;
             }
@@ -630,7 +722,7 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
 
     }
 
-    private JSONArray getPlayletDetail(String advertiserId, String accessToken, String instanceId, Set<String> errorBlanket, Integer pageNum) {
+    private JSONArray getPlayletDetail(String advertiserId, String accessToken, String instanceId, Set<ErrorRecord> errorBlanket, Integer pageNum, String platformId) {
         if (pageNum >60){
             return new JSONArray();
         }
@@ -650,14 +742,14 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
         }
 
         if (res == null || res.isEmpty()) {
-            errorBlanket.add("获取字节小程序推广链接失败, 广告账号ID:" + advertiserId + ", 小程序资产ID:" + instanceId);
+            errorBlanket.add(new ErrorRecord("获取字节小程序推广链接失败, 广告账号ID:" + advertiserId + ", 小程序资产ID:" + instanceId, null, platformId));
             System.out.println("获取字节小程序推广链接失败, 广告账号ID:" + advertiserId + ", 小程序资产ID:" + instanceId);
             return new JSONArray();
         }else {
             JSONObject jsonObject = JSONObject.parseObject(res);
             int code = jsonObject.getIntValue("code");
             if (code != 0) {
-                errorBlanket.add("获取字节小程序推广链接失败,code: " + code + ", msg: " + jsonObject.getString("message") + ", 广告账号ID:" + advertiserId + ", 小程序资产ID:" + instanceId);
+                errorBlanket.add(new ErrorRecord("获取字节小程序推广链接失败,code: " + code + ", msg: " + jsonObject.getString("message") + ", 广告账号ID:" + advertiserId + ", 小程序资产ID:" + instanceId, null, platformId));
                 System.out.println("获取字节小程序推广链接失败,code: " + code + ", msg: " + jsonObject.getString("message") + ", 广告账号ID:" + advertiserId + ", 小程序资产ID:" + instanceId);
                 return new JSONArray();
             }else {
@@ -999,6 +1091,7 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
         List<JSONObject> videoDetailList = new ArrayList<>();
         for (JSONObject obj : videoDetail){
             String videoUrl = obj.getString("url").replaceAll("oss\\.artlinkworld\\.cn", "bydance.artlinkworld.cn");//使用单独的域名
+
             String title = obj.getString("name");
             Integer seq = obj.getInteger("sort");
 

+ 1 - 1
job-bytedance/src/main/java/cn/com/ctop/job/bytedance/utils/RateLimitUtil.java

@@ -63,6 +63,6 @@ public class RateLimitUtil {
             );
             initMap.put(key, true);
         }
-        return redissonClient.getRateLimiter(key).tryAcquire(1, 1, TimeUnit.SECONDS);
+        return redissonClient.getRateLimiter(key).tryAcquire(1, 5, TimeUnit.SECONDS);
     }
 }