From e138d9d0477af47d215c6d1f6db0ed216d3a87c3 Mon Sep 17 00:00:00 2001 From: UNGGU0704 Date: Tue, 17 Jun 2025 15:11:28 +0900 Subject: [PATCH] =?UTF-8?q?Fix:=20redis=20=EC=84=A4=EC=A0=95=20=EB=B0=8F?= =?UTF-8?q?=20=EC=A0=80=EC=9E=A5=20=ED=98=95=EC=8B=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gateway/ExternalPlatformAdapter.java | 73 +++++++------------ store/src/main/resources/application.yml | 7 ++ 2 files changed, 32 insertions(+), 48 deletions(-) diff --git a/store/src/main/java/com/ktds/hi/store/infra/gateway/ExternalPlatformAdapter.java b/store/src/main/java/com/ktds/hi/store/infra/gateway/ExternalPlatformAdapter.java index 61f4533..8530edb 100644 --- a/store/src/main/java/com/ktds/hi/store/infra/gateway/ExternalPlatformAdapter.java +++ b/store/src/main/java/com/ktds/hi/store/infra/gateway/ExternalPlatformAdapter.java @@ -144,37 +144,40 @@ public class ExternalPlatformAdapter implements ExternalPlatformPort { } } - /** - * 카카오 응답 파싱 및 Redis 저장 (실제 응답 구조에 맞게 완전 수정) + * 카카오 응답 파싱 및 Redis 저장 (단순화된 안정적인 방식) */ private int parseAndStoreToRedis(Long storeId, String platform, String responseBody) { try { log.info("카카오 API 응답: {}", responseBody); - // JSON 파싱 - JsonNode rootNode = objectMapper.readTree(responseBody); + if (responseBody == null || responseBody.trim().isEmpty()) { + log.warn("카카오 응답이 비어있음: storeId={}", storeId); + return 0; + } - // 🔥 실제 카카오 크롤링 서비스 응답 구조 체크 - if (!rootNode.has("success") || !rootNode.get("success").asBoolean()) { + JsonNode root = objectMapper.readTree(responseBody); + + // 🔥 실제 카카오 응답 구조에 맞는 파싱 + if (!root.has("success") || !root.get("success").asBoolean()) { log.warn("카카오 API 응답 실패: {}", responseBody); updateSyncStatus(storeId, platform, "FAILED", 0); return 0; } - JsonNode reviewsNode = rootNode.get("reviews"); + JsonNode reviewsNode = root.get("reviews"); if (reviewsNode == null || !reviewsNode.isArray()) { log.warn("카카오 응답에 reviews 배열이 없음"); updateSyncStatus(storeId, platform, "SUCCESS", 0); return 0; } - // 🔥 실제 카카오 응답 구조에 맞는 리뷰 데이터 변환 - List> parsedReviews = new ArrayList<>(); + // 리뷰 데이터 파싱 + List> reviews = new ArrayList<>(); for (JsonNode reviewNode : reviewsNode) { Map review = new HashMap<>(); - // 🔑 기본 리뷰 정보 (실제 필드명 사용) + // 기본 정보 review.put("reviewId", generateReviewId(reviewNode)); review.put("content", reviewNode.path("content").asText("")); review.put("rating", reviewNode.path("rating").asDouble(0.0)); @@ -182,67 +185,41 @@ public class ExternalPlatformAdapter implements ExternalPlatformPort { review.put("createdAt", reviewNode.path("date").asText("")); review.put("platform", platform); - // 🏷️ 카카오 특화 정보 + // 카카오 특화 정보 review.put("reviewerLevel", reviewNode.path("reviewer_level").asText("")); review.put("likes", reviewNode.path("likes").asInt(0)); review.put("photoCount", reviewNode.path("photo_count").asInt(0)); review.put("hasPhotos", reviewNode.path("has_photos").asBoolean(false)); - // 📊 리뷰어 통계 (있는 경우만) - if (reviewNode.has("reviewer_stats")) { - JsonNode stats = reviewNode.get("reviewer_stats"); - Map reviewerStats = new HashMap<>(); - reviewerStats.put("reviews", stats.path("reviews").asInt(0)); - reviewerStats.put("averageRating", stats.path("average_rating").asDouble(0.0)); - reviewerStats.put("followers", stats.path("followers").asInt(0)); - review.put("reviewerStats", reviewerStats); - } - - // 🏆 배지 (있는 경우만) + // 배지 정보 if (reviewNode.has("badges") && reviewNode.get("badges").isArray()) { List badges = new ArrayList<>(); - for (JsonNode badge : reviewNode.get("badges")) { - badges.add(badge.asText()); - } + reviewNode.get("badges").forEach(badge -> badges.add(badge.asText())); review.put("badges", badges); } - parsedReviews.add(review); + reviews.add(review); } - if (!parsedReviews.isEmpty()) { - // 🔥 Redis에 저장 - log.info("Redis에 리뷰 데이터 저장 진행 중"); - String redisKey = String.format("external:reviews:pending:%d:%s:%d", - storeId, platform, System.currentTimeMillis()); + log.info("파싱된 리뷰 수: {}", reviews.size()); - Map cacheData = new HashMap<>(); - cacheData.put("storeId", storeId); - cacheData.put("platform", platform); - cacheData.put("reviews", parsedReviews); - cacheData.put("status", "PENDING"); - cacheData.put("timestamp", System.currentTimeMillis()); - cacheData.put("retryCount", 0); + // Redis 저장 (단순한 방식) + saveToRedis(storeId, platform, reviews); - redisTemplate.opsForValue().set(redisKey, cacheData, Duration.ofDays(1)); + // 동기화 상태 업데이트 + updateSyncStatus(storeId, platform, "SUCCESS", reviews.size()); - log.info("Redis에 리뷰 데이터 저장 완료: key={}, count={}", redisKey, parsedReviews.size()); - - // 🔥 동기화 상태 업데이트 - updateSyncStatus(storeId, platform, "SUCCESS", parsedReviews.size()); - } - - return parsedReviews.size(); + return reviews.size(); } catch (Exception e) { - log.error("카카오 응답 파싱 및 Redis 저장 실패: storeId={}, error={}", storeId, e.getMessage()); - e.printStackTrace(); + log.error("카카오 응답 파싱 및 Redis 저장 실패: storeId={}, error={}", storeId, e.getMessage(), e); updateSyncStatus(storeId, platform, "FAILED", 0); return 0; } } + /** * 🔥 누락된 generateReviewId 메서드 추가 */ diff --git a/store/src/main/resources/application.yml b/store/src/main/resources/application.yml index ee1a5f1..ee056a3 100644 --- a/store/src/main/resources/application.yml +++ b/store/src/main/resources/application.yml @@ -29,6 +29,13 @@ spring: host: ${REDIS_HOST:localhost} port: ${REDIS_PORT:6379} password: ${REDIS_PASSWORD:} + timeout: 2000ms + lettuce: + pool: + max-active: 8 + max-wait: -1ms + max-idle: 8 + min-idle: 0 external-api: naver: