Przeglądaj źródła

recommend add lock

wangyunpeng 1 dzień temu
rodzic
commit
b1819e89b5

+ 57 - 35
long-article-recommend-service/src/main/java/com/tzld/longarticle/recommend/server/service/recommend/RecommendService.java

@@ -112,49 +112,71 @@ public class RecommendService {
 
     public RecommendResponse recommend(RecommendRequest request) {
         long start = System.currentTimeMillis();
-        RecommendParam param = genRecommendParam(request, SceneConstants.DEFAULT);
-        log.info("genRecommendParam {}", JSONUtils.toJson(param));
-        // 获取账号排序设置
-        setStrategy(request, param);
 
-        // 获取 video-article match 结果(仅配置中的账号,当日缓存)
-        Map<String, String> sourceIdToExperimentId = videoArticleMatchAccountList.contains(request.getAccountName())
-                ? fetchSourceIdToExperimentId(request.getAccountName())
-                : Collections.emptyMap();
+        // 基于 planId + accountId 的分布式锁,防止并发重复执行
+        String lockKey = null;
+        String requestId = null;
+        if (StringUtils.hasText(request.getPlanId()) && StringUtils.hasText(request.getAccountId())) {
+            lockKey = "recommend-lock:" + request.getPlanId() + ":" + request.getAccountId();
+            requestId = UUID.randomUUID().toString();
+            if (!redisUtil.tryAcquireLock(lockKey, requestId, 600L)) {
+                log.info("recommend is already processing, skip. planId:{}, accountId:{}", request.getPlanId(), request.getAccountId());
+                RecommendResponse response = new RecommendResponse();
+                response.setCode(0);
+                response.setMsg("success");
+                return response;
+            }
+        }
 
-        RecallResult recallResult = recallService.recall(convertToRecallParam(param));
+        try {
+            RecommendParam param = genRecommendParam(request, SceneConstants.DEFAULT);
+            log.info("genRecommendParam {}", JSONUtils.toJson(param));
+            // 获取账号排序设置
+            setStrategy(request, param);
 
-        filterRecallBySourceId(recallResult, sourceIdToExperimentId);
+            // 获取 video-article match 结果(仅配置中的账号,当日缓存)
+            Map<String, String> sourceIdToExperimentId = videoArticleMatchAccountList.contains(request.getAccountName())
+                    ? fetchSourceIdToExperimentId(request.getAccountName())
+                    : Collections.emptyMap();
 
-        if (CollectionUtils.isEmpty(recallResult.getData())) {
-            RecommendResponse response = new RecommendResponse();
-            response.setCode(0);
-            response.setMsg("success");
-            return response;
-        }
-        long t2 = System.currentTimeMillis();
-        CostMonitor.logCost("Recommend", "Recall", t2 - start);
-        RankResult rankResult = rankService.rank(convertToRankParam(param, recallResult));
-        long t3 = System.currentTimeMillis();
-        CostMonitor.logCost("Recommend", "Rank", t3 - t2);
-        excludeArticleIndex(rankResult, request.getExcludeContentIndex());
-        saveSortLog(param, rankResult);
+            RecallResult recallResult = recallService.recall(convertToRecallParam(param));
 
-        RecommendResponse response = buildRecommendResponse(recallResult, rankResult, param.getPublishNum());
-        // 设置每个 item 的 experimentId
-        if (CollectionUtils.isNotEmpty(sourceIdToExperimentId.keySet())) {
-            for (ArticleSortResponseDataItem item : response.getData().getRank_list()) {
-                String expId = sourceIdToExperimentId.get(item.getSourceId());
-                if (expId != null) {
-                    item.setExperimentId(expId);
+            filterRecallBySourceId(recallResult, sourceIdToExperimentId);
+
+            if (CollectionUtils.isEmpty(recallResult.getData())) {
+                RecommendResponse response = new RecommendResponse();
+                response.setCode(0);
+                response.setMsg("success");
+                return response;
+            }
+            long t2 = System.currentTimeMillis();
+            CostMonitor.logCost("Recommend", "Recall", t2 - start);
+            RankResult rankResult = rankService.rank(convertToRankParam(param, recallResult));
+            long t3 = System.currentTimeMillis();
+            CostMonitor.logCost("Recommend", "Rank", t3 - t2);
+            excludeArticleIndex(rankResult, request.getExcludeContentIndex());
+            saveSortLog(param, rankResult);
+
+            RecommendResponse response = buildRecommendResponse(recallResult, rankResult, param.getPublishNum());
+            // 设置每个 item 的 experimentId
+            if (CollectionUtils.isNotEmpty(sourceIdToExperimentId.keySet())) {
+                for (ArticleSortResponseDataItem item : response.getData().getRank_list()) {
+                    String expId = sourceIdToExperimentId.get(item.getSourceId());
+                    if (expId != null) {
+                        item.setExperimentId(expId);
+                    }
                 }
             }
+            long t4 = System.currentTimeMillis();
+            log.info("recommendCost param:{} total cost:{} recall:{} rank:{} response: {}", JSONObject.toJSONString(request),
+                    t4 - start, t2 - start, t3 - t2, JSONObject.toJSONString(response));
+            CostMonitor.logCost("Recommend", "Total", t4 - start);
+            return response;
+        } finally {
+            if (lockKey != null) {
+                redisUtil.releaseLock(lockKey, requestId);
+            }
         }
-        long t4 = System.currentTimeMillis();
-        log.info("recommendCost param:{} total cost:{} recall:{} rank:{} response: {}", JSONObject.toJSONString(request),
-                t4 - start, t2 - start, t3 - t2, JSONObject.toJSONString(response));
-        CostMonitor.logCost("Recommend", "Total", t4 - start);
-        return response;
     }
 
     /**