본문으로 건너뛰기

추천 파이프라인

이 문서로 해결할 질문​

  • Consumer가 추천 점수를 어떻게 갱신하나요?
  • user-events·activity-events 중 어떤 이벤트가 UserRecipeRecommendation에 반영되나요?
  • Top N 재정렬·캐시 무효화는 어떤 순서로 일어나나요?
  • 추천 반영이 느릴 때 어디를 확인하나요?

Consumer 책임​

Producer가 발행한 Kafka 이벤트를 소비해 PostgreSQL user_recipe_recommendations 원본 테이블의 점수를 갱신하고, cache-invalidation 토픽으로 recommendation:{userId} Redis 키 삭제를 요청합니다.

조회·캐시·API 응답은 Producer가 담당합니다. 전체 흐름은 추천 시스템을 참고하세요.

Kafka 진입점​

토픽그룹핸들러DLQ
user-eventsanalytics-groupRecommendationHandleruser-events-dlq
activity-eventsactivity-events-groupActivityRecommendationServiceactivity-events-dlq

user-events processor는 프로필·재고 갱신 후 항상 RecommendationHandler를 호출합니다. activity-events는 EventLog 저장·조회수 증가 후 추천 보정을 시도하며, 추천 실패만 warn 로그로 남기고 offset commit은 계속합니다.

처리 흐름​

점수 갱신 알고리즘​

RecommendationRepository가 단일 트랜잭션으로 다음을 수행합니다.

  1. 이벤트별 score delta를 (userId, recipeId)에 upsert합니다. 신규 행은 임시 rank(9999 + recipeId)로 충돌을 방지합니다.
  2. score > 0 후보를 score DESC → updatedAt DESC → recipeId ASC 순으로 정렬합니다.
  3. 해당 사용자의 행을 모두 삭제한 뒤 상위 10건(MAX_RECOMMENDATION_ROWS)만 rank 1..N으로 다시 작성합니다.

재료 이벤트는 recipe_ingredients에서 연관 recipeId를 조회(최대 200건)한 뒤, 각 레시피에 동일 delta를 적용합니다.

user-events 가중치​

RecommendationScoreService가 처리합니다. signup·login·nickname.update·userId <= 0은 무시합니다.

이벤트delta적용 대상
recipe.favorites_add+1.8favoriteRecipeIds
recipe.favorites_remove-1.8recipeId
ingredient.favorites_add+0.8연관 레시피
ingredient.favorites_remove-0.8연관 레시피
ingredient.favorites_update+0.5연관 레시피
ingredient.add+0.25연관 레시피
ingredient.update+0.15연관 레시피
ingredient.remove-0.2연관 레시피

activity-events 가중치​

ActivityRecommendationService가 처리합니다. 로그인 사용자(actor.userId > 0)이고 recipeId를 resolve할 수 있을 때만 반영합니다.

이벤트delta비고
recipe.view+0.1entity.type === 'recipe' 또는 payload.recipeId
recipe.share+0.4동일
search.click+0.25클릭한 레시피 ID
search.query—delta 0, 추천 미반영

recipe.view의 조회수 증가(Recipe.viewCount)는 추천과 별도로 ActivityEventsProcessor에서 처리합니다.

캐시 무효화​

점수 갱신 직후 CacheInvalidationRequestService.requestRecommendationInvalidation(userId)를 호출합니다.

항목값
발행 토픽cache-invalidation
payload typeRECOMMENDATION
삭제 키recommendation:{userId}

캐시 무효화 절차는 캐시 무효화를 참고하세요.

신뢰성​

항목동작
전달 보장at-least-once — (userId, recipeId) upsert로 중복 delta 안전
user-events 실패processor 전체 재시도 → user-events-dlq
activity-events 추천 실패warn 로그만, EventLog·조회수 처리는 유지
파티션 키cache-invalidation은 userId 기준 순서 보장

주요 구현 경로​

항목경로
user-events processorserver/consumer/.../user-events.processor.ts
user-events 핸들러server/consumer/.../RecommendationHandler.ts
user-events 점수server/consumer/.../recommendation-score.service.ts
activity-events 보정server/consumer/.../activity-recommendation.service.ts
원본 테이블·Top Nserver/consumer/.../recommendation.repository.ts
Top N 상한@mealio/shared MAX_RECOMMENDATION_ROWS (= 10)

운영·KPI​

  • E2E 지연 KPI kpi_recommendation_e2e_latency는 EventLog recipe.favorites_add의 occurredAt부터 processedAt까지 p95를 측정합니다.
  • 일별 롤업은 server/consumer/.../kpi-rollup.service.ts cron 잡이 담당합니다.
  • 지연 알림은 Observability와 Consumer 운영 — 추천 반영 지연을 참고하세요.

지연 발생 시 확인 순서는 user-events lag → RecommendationHandler DB 트랜잭션 → activity-events warn 로그입니다.

변경 시 체크리스트​

  1. 가중치를 변경하면 recommendation-score.service.ts와 activity-recommendation.service.ts를 수정하고 추천 시스템 요약 표를 갱신합니다.
  2. Top N 상한을 변경하면 recommendation.policy.ts의 MAX_RECOMMENDATION_ROWS와 Producer GET /recipes/recommended limit을 함께 맞춥니다.
  3. 캐시 키를 변경하면 Redis 키/캐시 계약과 producer 캐시를 함께 갱신합니다.

관련 문서​