Преглед изворни кода

add:门店装修动态审核,视频审核变为异步审核

刘云鑫 пре 3 месеци
родитељ
комит
51a84ab6dc

+ 102 - 8
alien-store/src/main/java/shop/alien/store/service/impl/StoreRenovationRequirementServiceImpl.java

@@ -21,7 +21,10 @@ import shop.alien.store.util.ai.AiContentModerationUtil;
 import shop.alien.store.util.ai.AiVideoModerationUtil;
 import shop.alien.util.common.JwtUtil;
 
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
 import java.util.*;
+import java.util.concurrent.*;
 import java.util.stream.Collectors;
 
 /**
@@ -36,6 +39,9 @@ import java.util.stream.Collectors;
 @Transactional(rollbackFor = Exception.class)
 public class StoreRenovationRequirementServiceImpl extends ServiceImpl<StoreRenovationRequirementMapper, StoreRenovationRequirement> implements StoreRenovationRequirementService {
 
+    // 1. 自定义视频审核线程池(全局复用,避免频繁创建线程)
+    private ExecutorService videoAuditExecutor;
+
     private final StoreInfoMapper storeInfoMapper;
 
     private final AiContentModerationUtil aiContentModerationUtil;
@@ -50,6 +56,55 @@ public class StoreRenovationRequirementServiceImpl extends ServiceImpl<StoreReno
             new HashSet<>(Arrays.asList(".mp4", ".avi", ".mov", ".flv", ".mkv", ".wmv", ".mpeg"))
     );
 
+    // 初始化线程池
+    @PostConstruct
+    public void initExecutor() {
+        // 核心参数根据业务调整,IO密集型任务线程数可设为CPU核心数*2~4
+        int corePoolSize = Runtime.getRuntime().availableProcessors() * 2;
+        int maxPoolSize = Runtime.getRuntime().availableProcessors() * 4;
+        videoAuditExecutor = new ThreadPoolExecutor(
+                corePoolSize,
+                maxPoolSize,
+                60L,
+                TimeUnit.SECONDS,
+                new LinkedBlockingQueue<>(500), // 任务队列,避免无界队列溢出
+                new ThreadFactory() {
+                    private int count = 0;
+                    @Override
+                    public Thread newThread(Runnable r) {
+                        Thread t = new Thread(r);
+                        t.setName("video-audit-" + count++); // 自定义线程名,便于排查
+                        return t;
+                    }
+                },
+                // 任务拒绝策略:记录日志+调用者线程兜底(避免任务丢失)
+                new ThreadPoolExecutor.CallerRunsPolicy() {
+                    @Override
+                    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
+                        log.error("视频审核任务被拒绝,队列已满!当前队列大小:{},活跃线程数:{}",
+                                e.getQueue().size(), e.getActiveCount());
+                        super.rejectedExecution(r, e);
+                    }
+                }
+        );
+    }
+
+    // 优雅关闭线程池
+    @PreDestroy
+    public void destroyExecutor() {
+        if (Objects.nonNull(videoAuditExecutor)) {
+            videoAuditExecutor.shutdown();
+            try {
+                if (!videoAuditExecutor.awaitTermination(30, TimeUnit.SECONDS)) {
+                    videoAuditExecutor.shutdownNow();
+                }
+            } catch (InterruptedException e) {
+                videoAuditExecutor.shutdownNow();
+                Thread.currentThread().interrupt();
+            }
+        }
+    }
+
     @Override
     public boolean saveOrUpdateRequirement(StoreRenovationRequirementDto dto) {
         log.info("StoreRenovationRequirementServiceImpl.saveOrUpdateRequirement?dto={}", dto);
@@ -104,15 +159,54 @@ public class StoreRenovationRequirementServiceImpl extends ServiceImpl<StoreReno
                 requirement.setAuditStatus(2);
                 requirement.setAuditReason(auditResult.getFailureReason());
             } else {
-                // 2.调用视频审核接口
-                AiVideoModerationUtil.VideoAuditResult videoAuditResult = aiVideoModerationUtil.auditVideos(urlCategoryMap.get("video"));
-                if (!videoAuditResult.isPassed()) {
-                    requirement.setAuditStatus(2);
-                    requirement.setAuditReason(videoAuditResult.getFailureReason());
-                }
-                requirement.setAuditStatus(1);
+                // 异步调用视频审核接口,图片审核通过后调用(核心优化)
+                CompletableFuture.runAsync(() -> {
+                    AiVideoModerationUtil.VideoAuditResult videoAuditResult = null;
+                    try {
+                        // 调用审核接口,增加超时控制(避免接口挂死)
+                        videoAuditResult = CompletableFuture.supplyAsync(
+                                () -> aiVideoModerationUtil.auditVideos(urlCategoryMap.get("video")),
+                                videoAuditExecutor
+                        ).get();
+
+                        // 审核不通过则更新状态和原因
+                        if (Objects.nonNull(videoAuditResult) && !videoAuditResult.isPassed()) {
+                            // 重新查询最新的requirement,避免并发覆盖
+                            StoreRenovationRequirement latestRequirement = this.getById(requirement.getId());
+                            if (Objects.isNull(latestRequirement)) {
+                                log.error("视频审核后更新失败,requirement不存在,ID:{}", requirement.getId());
+                                return;
+                            }
+                            latestRequirement.setAuditStatus(2);
+                            latestRequirement.setAuditReason(videoAuditResult.getFailureReason());
+                            this.saveOrUpdate(latestRequirement);
+                            log.info("视频审核不通过,已更新状态,requirementID:{},原因:{}",
+                                    requirement.getId(), videoAuditResult.getFailureReason());
+                        } else if (Objects.nonNull(videoAuditResult) && videoAuditResult.isPassed()) {
+                            // 审核通过也更新状态(可选,根据业务需求)
+                            StoreRenovationRequirement latestRequirement = this.getById(requirement.getId());
+                            if (Objects.nonNull(latestRequirement)) {
+                                latestRequirement.setAuditStatus(1);
+                                latestRequirement.setAuditReason(null);
+                                this.saveOrUpdate(latestRequirement);
+                                log.info("视频审核通过,已更新状态,requirementID:{}", requirement.getId());
+                            }
+                        }
+                    } catch (Exception e) {
+                        log.error("视频审核接口调用异常,requirementID:{}", requirement.getId(), e);
+                        StoreRenovationRequirement latestRequirement = this.getById(requirement.getId());
+                        if (Objects.nonNull(latestRequirement)) {
+                            latestRequirement.setAuditStatus(2);
+                            latestRequirement.setAuditReason("视频审核接口调用异常:" + e.getMessage()); // 实际需捕获具体异常信息
+                            this.saveOrUpdate(latestRequirement);
+                        }
+                    }
+                }, videoAuditExecutor);
             }
-            return this.saveOrUpdate(requirement);
+            requirement.setAuditTime(new Date());
+            boolean isSuccess  = this.saveOrUpdate(requirement);
+
+            return isSuccess;
         } catch (Exception e) {
             log.error("保存装修需求失败: {}", e.getMessage(), e);
             throw new RuntimeException("保存装修需求失败: " + e.getMessage());