Ver código fonte

feat:虚拟线程执行计划创建

pudongliang 4 meses atrás
pai
commit
aa85c8a495

+ 1 - 0
.qoder/rules/always_on_rule.md

@@ -11,6 +11,7 @@ trigger: always_on
 不要读取resources目录下的配置文件,需要时给出确认提示
 不要读取target, node_modules, dist目录下的内容
 不要读取.gitignore中提到的目录与文件
+关键逻辑写上中文注释
 
 
 # CRUD代码参考

+ 1 - 0
src/main/java/com/moka/gdtauto/common/Constant.java

@@ -5,6 +5,7 @@ import java.util.Map;
 
 public class Constant {
     public static final Long MAIN_ORG_ACCOUNT_ID = 41644744L;
+    public static final String JOB_NUMBER  = "11203";
 
     /**
      * ADGROUP_STATUS_FROZEN, // 已冻结

+ 97 - 53
src/main/java/com/moka/gdtauto/service/impl/AdPlanConfServiceImpl.java

@@ -9,6 +9,10 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
@@ -588,66 +592,106 @@ public class AdPlanConfServiceImpl extends ServiceImpl<AdPlanConfMapper, AdPlanC
             return;
         }
 
-        // 第二步:创建广告组与创意
-        // 遍历处理每个 AdPlan
+        // 第二步:创建广告组与创意(使用虚拟线程并行处理,Semaphore限制最大并发数为10)
+        Semaphore semaphore = new Semaphore(10);
+        CountDownLatch latch = new CountDownLatch(plans.size());
+        ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
+        
         for (AdPlan plan : plans) {
-            try {
-                log.info("开始处理广告计划,planId={}, adgroupName={}", plan.getId(), plan.getAdgroupName());
+            executor.submit(() -> {
+                try {
+                    semaphore.acquire();
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                    latch.countDown();
+                    return;
+                }
+                
+                // 每个虚拟线程创建独立的 TencentAds 实例
+                TencentAds threadTencentAds;
+                try {
+                    threadTencentAds = clientFactory.getTencentAds(jobNumber, Constant.MAIN_ORG_ACCOUNT_ID);
+                } catch (Exception e) {
+                    log.error("虚拟线程创建TencentAds实例失败,planId={}", plan.getId(), e);
+                    plan.setStatus(AdPlanStatus.FAILED);
+                    plan.setFailReason("创建TencentAds实例失败: " + StrUtil.truncateError(e.getMessage()));
+                    adPlanService.updateById(plan);
+                    semaphore.release();
+                    latch.countDown();
+                    return;
+                }
+                
+                try {
+                    log.info("开始处理广告计划,planId={}, adgroupName={}", plan.getId(), plan.getAdgroupName());
+
+                    if (plan.getAdgroupId() > 0 || plan.getStatus() == AdPlanStatus.SUCCESS) {
+                        // 创建动态创意
+                        createDynamicCreatives(threadTencentAds, plan);
+                        plan.setFailReason("");
+                        plan.setStatus(AdPlanStatus.SUCCESS);
+                        plan.setSuccessTime(LocalDateTime.now());
+                        adPlanService.updateById(plan);
+                        return;
+                    }
 
-                if (plan.getAdgroupId() > 0 || plan.getStatus() == AdPlanStatus.SUCCESS) {
-                    // 创建动态创意
-                    createDynamicCreatives(tencentAds, plan);
-                    plan.setFailReason("");
+                    // 更新状态为执行中
+                    plan.setStatus(AdPlanStatus.IN_PROGRESS);
+                    adPlanService.updateById(plan);
+
+                    // 根据 adType 构建请求
+                    AdgroupsAddRequest request = buildAdgroupRequest(plan);
+                    log.info("请求参数: {}", JSON.toJSON(request));
+                    // 创建广告组
+                    log.info("调用腾讯API创建广告组,accountId={}, orgAccountId={}", plan.getAccountId(),
+                            Constant.MAIN_ORG_ACCOUNT_ID);
+                    AdgroupsAddResponseData response = tencentAdsAdgroupService.createAdgroup(
+                            threadTencentAds, request);
+
+                    // 更新 adgroupId
+                    plan.setAdgroupId(response.getAdgroupId());
+                    log.info("广告组创建成功,adgroupId={}", response.getAdgroupId());
+
+                    // 更新状态为成功
                     plan.setStatus(AdPlanStatus.SUCCESS);
+                    plan.setFailReason("");
+                    plan.setCreateTime(LocalDateTime.now());
                     plan.setSuccessTime(LocalDateTime.now());
                     adPlanService.updateById(plan);
-                    continue;
-                }
 
-                // 更新状态为执行中
-                plan.setStatus(AdPlanStatus.IN_PROGRESS);
-                adPlanService.updateById(plan);
-
-                // 根据 adType 构建请求
-                AdgroupsAddRequest request = buildAdgroupRequest(plan);
-                log.info("请求参数: {}", JSON.toJSON(request));
-                // 创建广告组
-                log.info("调用腾讯API创建广告组,accountId={}, orgAccountId={}", plan.getAccountId(),
-                        Constant.MAIN_ORG_ACCOUNT_ID);
-                AdgroupsAddResponseData response = tencentAdsAdgroupService.createAdgroup(
-                        tencentAds, request);
-
-                // 更新 adgroupId
-                plan.setAdgroupId(response.getAdgroupId());
-                log.info("广告组创建成功,adgroupId={}", response.getAdgroupId());
-
-                // 更新状态为成功
-                plan.setStatus(AdPlanStatus.SUCCESS);
-                plan.setFailReason("");
-                plan.setCreateTime(LocalDateTime.now());
-                plan.setSuccessTime(LocalDateTime.now());
-                adPlanService.updateById(plan);
-
-                // 创建动态创意
-                if (plan.getAdgroupId() > 0) {
-                    createDynamicCreatives(tencentAds, plan);
-                }
+                    // 创建动态创意
+                    if (plan.getAdgroupId() > 0) {
+                        createDynamicCreatives(threadTencentAds, plan);
+                    }
 
-                log.info("广告计划处理成功,planId={}, adgroupId={}", plan.getId(), plan.getAdgroupId());
+                    log.info("广告计划处理成功,planId={}, adgroupId={}", plan.getId(), plan.getAdgroupId());
 
-            } catch (TencentAdsResponseException e) {
-                // 记录失败
-                log.error("创建广告失败, planId={} code={} message={} messageCn={}", plan.getId(), e.getCode(),
-                        e.getMessage(), e.getMessageCn());
-                plan.setStatus(AdPlanStatus.FAILED);
-                plan.setFailReason(StrUtil.truncateError(e.getMessageCn()));
-                adPlanService.updateById(plan);
-            } catch (Exception e) {
-                log.error("创建广告失败, planId={}", plan.getId(), e);
-                plan.setStatus(AdPlanStatus.FAILED);
-                plan.setFailReason(StrUtil.truncateError(e.getMessage()));
-                adPlanService.updateById(plan);
-            }
+                } catch (TencentAdsResponseException e) {
+                    // 记录失败
+                    log.error("创建广告失败, planId={} code={} message={} messageCn={}", plan.getId(), e.getCode(),
+                            e.getMessage(), e.getMessageCn());
+                    plan.setStatus(AdPlanStatus.FAILED);
+                    plan.setFailReason(StrUtil.truncateError(e.getMessageCn()));
+                    adPlanService.updateById(plan);
+                } catch (Exception e) {
+                    log.error("创建广告失败, planId={}", plan.getId(), e);
+                    plan.setStatus(AdPlanStatus.FAILED);
+                    plan.setFailReason(StrUtil.truncateError(e.getMessage()));
+                    adPlanService.updateById(plan);
+                } finally {
+                    semaphore.release();
+                    latch.countDown();
+                }
+            });
+        }
+        
+        // 等待所有虚拟线程任务完成
+        try {
+            latch.await();
+        } catch (InterruptedException e) {
+            log.error("等待虚拟线程任务完成被中断,confId={}", confId, e);
+            Thread.currentThread().interrupt();
+        } finally {
+            executor.shutdown();
         }
 
         // 更新 AdPlanConf 状态
@@ -1085,7 +1129,7 @@ public class AdPlanConfServiceImpl extends ServiceImpl<AdPlanConfMapper, AdPlanC
                 return;
             }
 
-            TencentAds tencentAds = clientFactory.getTencentAds(null, Constant.MAIN_ORG_ACCOUNT_ID);
+            TencentAds tencentAds = clientFactory.getTencentAds(Constant.JOB_NUMBER, Constant.MAIN_ORG_ACCOUNT_ID);
             doDeletePlans(tencentAds, deletePlans);
             lambdaUpdate().eq(AdPlanConf::getId, conf.getId())
                     .set(AdPlanConf::getFailReason, "广告巡检删除" + deletePlans.size() + "个广告")

+ 7 - 2
src/test/java/com/moka/gdtauto/service/AdAutoDeleteTest.java

@@ -1,5 +1,7 @@
 package com.moka.gdtauto.service;
 
+import java.util.List;
+
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
@@ -16,7 +18,10 @@ public class AdAutoDeleteTest {
 
     @Test
     public void testDelete() {
-        AdPlanConf adPlanConf = adPlanConfService.getById(2L);
-        adPlanConfService.gdtAdgroupPatrolDelete(adPlanConf);
+        List<Long> confIds = List.of(36L,37L,43L,44L,45L,51L);
+        for (Long confId : confIds) {
+            AdPlanConf adPlanConf = adPlanConfService.getById(confId);
+            adPlanConfService.gdtAdgroupPatrolDelete(adPlanConf);
+        }
     }
 }