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

小程序投流 P0 修复:
1) 权限统一:xcxPlanSave / xcxPlanDelete 由仅 type==2 放宽至 type==2 || type==3,与 xcxPlanMultiLink 对齐;否则代理商能复制多链接却删不掉,造成 garbage 数据。
2) 多链接补偿:xcxPlanMultiLink 循环包 try/catch,中途任一次 messageAttachmentService.getPageNoCache 或 DB 写入失败时,通过 rollbackXcxPlans 把已写入的 xcx_plan 软删(status=DELETED),避免重试堆积垃圾;异常重抛 SYSTEM_ERROR。不加 @Transactional 以免持有 DB 事务等 200 次外部 RPC。

刘立冬 16 часов назад
Родитель
Сommit
f82160a1a4

+ 51 - 28
api-module/src/main/java/com/tzld/piaoquan/api/service/contentplatform/impl/ContentPlatformPlanServiceImpl.java

@@ -2066,7 +2066,7 @@ public class ContentPlatformPlanServiceImpl implements ContentPlatformPlanServic
     @Override
     public List<XcxPlanItemVO> xcxPlanSave(XcxPlanSaveParam param) {
         ContentPlatformAccount loginUser = LoginUserContext.getUser();
-        if (!Objects.equals(loginUser.getType(), 2)) {
+        if (!Objects.equals(loginUser.getType(), 2) && !Objects.equals(loginUser.getType(), 3)) {
             throw new CommonException(ExceptionEnum.XCX_PLAN_INTERNAL_ONLY);
         }
         Long now = System.currentTimeMillis();
@@ -2099,7 +2099,7 @@ public class ContentPlatformPlanServiceImpl implements ContentPlatformPlanServic
     @Override
     public void xcxPlanDelete(Long id) {
         ContentPlatformAccount loginUser = LoginUserContext.getUser();
-        if (!Objects.equals(loginUser.getType(), 2)) {
+        if (!Objects.equals(loginUser.getType(), 2) && !Objects.equals(loginUser.getType(), 3)) {
             throw new CommonException(ExceptionEnum.XCX_PLAN_INTERNAL_ONLY);
         }
         ContentPlatformXcxPlan plan = xcxPlanMapper.selectByPrimaryKey(id);
@@ -2136,36 +2136,59 @@ public class ContentPlatformPlanServiceImpl implements ContentPlatformPlanServic
 
         Long now = System.currentTimeMillis();
         List<ContentPlatformXcxPlan> created = new ArrayList<>();
-        for (int i = 0; i < param.getCount(); i++) {
-            ContentPlatformXcxPlan xcxPlan = new ContentPlatformXcxPlan();
-            xcxPlan.setAudiencePackage(src.getAudiencePackage());
-            xcxPlan.setRemark(src.getRemark());
-            Staff staff = new Staff();
-            staff.setCarrierId("wxf7261ed54f2e450e");
-            staff.setRemark(src.getRemark());
-            String pageUrl = messageAttachmentService.getPageNoCache("touliu", "tencent", staff,
-                    srcVideo.getVideoId(), "小程序", null, null, srcVideo.getExperimentId());
-            String rootSourceId = MessageUtil.getRootSourceId(pageUrl);
-            xcxPlan.setPageUrl(pageUrl);
-            xcxPlan.setRootSourceId(rootSourceId);
-            xcxPlan.setStatus(PlanStatusEnum.NORMAL.getVal());
-            xcxPlan.setCreateAccountId(loginUser.getId());
-            xcxPlan.setCreateTimestamp(now);
-            xcxPlan.setUpdateTimestamp(now);
-            planMapperExt.insertXcxPlanReturnId(xcxPlan);
-            created.add(xcxPlan);
-
-            XcxPlanSaveVideoParam vp = new XcxPlanSaveVideoParam();
-            vp.setVideoId(srcVideo.getVideoId());
-            vp.setTitle(srcVideo.getTitle());
-            vp.setCover(srcVideo.getCover());
-            vp.setVideo(srcVideo.getVideo());
-            vp.setExperimentId(srcVideo.getExperimentId());
-            saveXcxPlanVideo(vp, xcxPlan.getId(), loginUser.getId());
+        try {
+            for (int i = 0; i < param.getCount(); i++) {
+                ContentPlatformXcxPlan xcxPlan = new ContentPlatformXcxPlan();
+                xcxPlan.setAudiencePackage(src.getAudiencePackage());
+                xcxPlan.setRemark(src.getRemark());
+                Staff staff = new Staff();
+                staff.setCarrierId("wxf7261ed54f2e450e");
+                staff.setRemark(src.getRemark());
+                String pageUrl = messageAttachmentService.getPageNoCache("touliu", "tencent", staff,
+                        srcVideo.getVideoId(), "小程序", null, null, srcVideo.getExperimentId());
+                String rootSourceId = MessageUtil.getRootSourceId(pageUrl);
+                xcxPlan.setPageUrl(pageUrl);
+                xcxPlan.setRootSourceId(rootSourceId);
+                xcxPlan.setStatus(PlanStatusEnum.NORMAL.getVal());
+                xcxPlan.setCreateAccountId(loginUser.getId());
+                xcxPlan.setCreateTimestamp(now);
+                xcxPlan.setUpdateTimestamp(now);
+                planMapperExt.insertXcxPlanReturnId(xcxPlan);
+                created.add(xcxPlan);
+
+                XcxPlanSaveVideoParam vp = new XcxPlanSaveVideoParam();
+                vp.setVideoId(srcVideo.getVideoId());
+                vp.setTitle(srcVideo.getTitle());
+                vp.setCover(srcVideo.getCover());
+                vp.setVideo(srcVideo.getVideo());
+                vp.setExperimentId(srcVideo.getExperimentId());
+                saveXcxPlanVideo(vp, xcxPlan.getId(), loginUser.getId());
+            }
+        } catch (Exception e) {
+            log.error("xcxPlanMultiLink failed at {}/{} for planId={}, rolling back {} created plans",
+                    created.size(), param.getCount(), param.getPlanId(), created.size(), e);
+            rollbackXcxPlans(created);
+            throw new CommonException(ExceptionEnum.SYSTEM_ERROR);
         }
         return buildXcxPlanItemVOList(created);
     }
 
+    private void rollbackXcxPlans(List<ContentPlatformXcxPlan> created) {
+        if (CollectionUtils.isEmpty(created)) {
+            return;
+        }
+        Long now = System.currentTimeMillis();
+        for (ContentPlatformXcxPlan plan : created) {
+            try {
+                plan.setStatus(PlanStatusEnum.DELETED.getVal());
+                plan.setUpdateTimestamp(now);
+                xcxPlanMapper.updateByPrimaryKeySelective(plan);
+            } catch (Exception ex) {
+                log.error("xcxPlanMultiLink rollback failed for planId={}", plan.getId(), ex);
+            }
+        }
+    }
+
     @Override
     public List<String> getXcxAudiencePackageList() {
         String dt = demandVideoMapperExt.getMaxDt(CHANNEL_NAME_XCX);