[25.01.16 / TASK-271] Hotfix - SVG Badge API 통계값 오류 해결 및 캐싱 적용#50
[25.01.16 / TASK-271] Hotfix - SVG Badge API 통계값 오류 해결 및 캐싱 적용#50Jihyun3478 merged 7 commits intomainfrom
Conversation
배지 API 데이터 정합성 오류 수정 - 다른 사용자 게시글이 섞여 조회되는 문제 해결 - 누적 조회수 중복 계산 오류 수정
배지 API 캐싱 및 쿼리 최적화 - Cache-Aside 패턴 적용 (TTL 10분) - IN 서브쿼리 → INNER JOIN 최적화
Walkthrough저장소의 두 쿼리( Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant Service as totalStats.service
participant Redis
participant Repo as totalStats.repository
participant DB
Client->>Service: getBadgeData(username, type, limit?, pastDateKST)
Service->>Redis: GET badge:{username}:{type}:{pastDateKST}
alt cache hit
Redis-->>Service: cached BadgeData
Service-->>Client: return cached BadgeData
else cache miss
Redis-->>Service: nil
Service->>Repo: getUserBadgeStats(username, pastDateKST)
Service->>Repo: getUserRecentPosts(username, limit, pastDateKST)
Repo->>DB: execute multi-CTE SQL queries
DB-->>Repo: query results
Repo-->>Service: aggregated stats + recent posts
Service->>Redis: SET badge:{username}:{type}:{pastDateKST} = BadgeData EX BADGE_CACHE_TTL
Redis-->>Service: OK
Service-->>Client: return BadgeData
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
시
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: Organization UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🧰 Additional context used🧬 Code graph analysis (1)src/services/totalStats.service.ts (2)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
🔇 Additional comments (3)
✏️ Tip: You can disable this entire section by setting Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/repositories/totalStats.repository.ts (1)
5-5: 파이프라인 실패: 사용되지 않는 import 제거 필요
getCurrentKSTDateString이 import되었지만 사용되지 않아 ESLint 에러가 발생합니다.🔧 수정 제안
-import { getCurrentKSTDateString, getKSTDateStringWithOffset } from '@/utils/date.util'; +import { getKSTDateStringWithOffset } from '@/utils/date.util';
🧹 Nitpick comments (2)
src/services/totalStats.service.ts (2)
55-59: 캐시 실패 시 graceful degradation 고려 권장현재 구현에서 Redis 장애 발생 시 전체 요청이 실패합니다. 배지 API의 가용성을 높이려면 캐시 실패 시에도 DB에서 데이터를 조회하도록 처리하는 것이 좋습니다.
♻️ 캐시 에러 핸들링 제안
- const cached = await cache.get<BadgeData>(cacheKey); - if (cached) { - logger.info(`[Cache HIT] ${cacheKey}`) - return cached; - } + try { + const cached = await cache.get<BadgeData>(cacheKey); + if (cached) { + logger.info(`[Cache HIT] ${cacheKey}`) + return cached; + } + } catch (cacheError) { + logger.warn(`[Cache GET Error] ${cacheKey}:`, cacheError); + // Redis 장애 시 DB에서 직접 조회 진행 + }
91-93: 캐시 저장 실패 시에도 결과 반환 권장캐시 저장 실패가 전체 요청 실패로 이어지지 않도록 처리하면 안정성이 향상됩니다.
♻️ 캐시 저장 에러 핸들링 제안
- await cache.set(cacheKey, result, BADGE_CACHE_TTL); - - return result; + try { + await cache.set(cacheKey, result, BADGE_CACHE_TTL); + } catch (cacheError) { + logger.warn(`[Cache SET Error] ${cacheKey}:`, cacheError); + } + + return result;
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/repositories/totalStats.repository.tssrc/services/totalStats.service.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2024-12-05T17:21:07.909Z
Learnt from: HA0N1
Repo: Check-Data-Out/velog-dashboard-v2-api PR: 6
File: src/reposities/user.repository.ts:7-15
Timestamp: 2024-12-05T17:21:07.909Z
Learning: Function `findByUserEmail` in `src/reposities/user.repository.ts` is scheduled to be deleted and should be ignored in future code reviews.
Applied to files:
src/repositories/totalStats.repository.ts
🧬 Code graph analysis (1)
src/services/totalStats.service.ts (3)
src/configs/cache.config.ts (1)
cache(17-17)src/types/dto/responses/totalStatsResponse.type.ts (1)
BadgeData(162-165)src/types/index.ts (1)
BadgeData(41-41)
🪛 GitHub Actions: Test CI
src/repositories/totalStats.repository.ts
[error] 5-5: ESLint: 'getCurrentKSTDateString' is defined but never used. (no-unused-vars)
🔇 Additional comments (4)
src/services/totalStats.service.ts (2)
15-16: LGTM! 캐시 TTL 설정이 적절합니다.10분(600초)의 TTL은 배지 데이터의 특성상 적절한 값입니다. Export하여 테스트에서도 활용할 수 있도록 한 점이 좋습니다.
72-89: LGTM! 결과 구조가 명확합니다.
BadgeData인터페이스에 맞게 결과를 구성하고,safeNumber유틸리티로 안전하게 숫자 변환을 처리하고 있습니다.src/repositories/totalStats.repository.ts (2)
115-152: LGTM! CTE 기반 쿼리가 PR 목표를 잘 달성합니다.
user_postsCTE에서JOIN users_user를 통해 특정 사용자의 게시글만 필터링하여 다른 사용자의 게시글 혼입 문제를 해결합니다.DISTINCT ON (post_id) ORDER BY date DESC패턴으로 각 게시글의 최신 통계만 정확히 가져옵니다.COALESCE를 적절히 사용하여 NULL 값을 안전하게 처리합니다.
167-206: LGTM! 쿼리 최적화가 잘 적용되었습니다.
user_postsCTE에서LIMIT을 먼저 적용하여 불필요한 JOIN을 줄였습니다.INNER JOIN을 통해 해당 사용자의 게시글만 조회되도록 보장합니다.- Line 199의
COALESCE(ls.total_view - ss.start_view, ls.total_view, 0)패턴이start_view가 NULL인 경우를 올바르게 처리합니다.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
six-standard
left a comment
There was a problem hiding this comment.
제 리뷰가 너무 늦어졌네요;;
코드 잘 읽었고, 큰 문제는 없는 것 같습니다..!
좋았던 점
- 쿼리 코드를 하단으로 분리하면서 비교적 코드를 읽기 편리했습니다
- 뱃지 캐시 TTL값 (매직넘버) 상수로 빼주신 점도 좋습니다!
ooheunda
left a comment
There was a problem hiding this comment.
코드 잘 봤습니다! 현우님이 먼저 꼼꼼히 남겨주셨고 수정도 잘 된 것 같아서 더 드릴 말씀은 없는 것 같네요! 고생하셨습니다~! 🔥👍
좋았던 점
- 복잡한 쿼리를 빌더 패턴으로 변경하시면서, 매개변수로 bool 값들을 받는 등 재사용에 대해 많이 고민하신 것 같아 좋았습니다!
Nuung
left a comment
There was a problem hiding this comment.
좋았던 점
- 전체적으로 빌더 패턴과 외부 인프라 독립적인 상황까지 업데이트 되어서 너무 깔끔해지고 좋은 것 같아요! 고생많으셨습니다!!
아쉬운 점
- 최종적은 PR 리뷰잉이라 여기까지 오면서 저희가 나눴던 코멘트들이 아쉬웠었지만 다 해결된 것 같아요!!
🔥 변경 사항
🏷 관련 이슈
#47📸 스크린샷 (UI 변경 시 필수)
(변경 사항이 UI와 관련된 경우 스크린샷을 첨부해주세요.)
📌 체크리스트
Summary by CodeRabbit
성능
Refactor
✏️ Tip: You can customize this high-level summary in your review settings.