Skip to content

[volume-7] Decoupling with Event#180

Closed
rnqhstmd wants to merge 70 commits intoLoopers-dev-lab:rnqhstmdfrom
rnqhstmd:round7
Closed

[volume-7] Decoupling with Event#180
rnqhstmd wants to merge 70 commits intoLoopers-dev-lab:rnqhstmdfrom
rnqhstmd:round7

Conversation

@rnqhstmd
Copy link
Copy Markdown
Collaborator

@rnqhstmd rnqhstmd commented Dec 12, 2025

📌 Summary

  • 주문 결제 플로우에서 외부 I/O 분리
  • 좋아요-집계 플로우에서 eventual consistency 적용
  • 이벤트 발행과 리스너를 활용하여 메인 트랜잭션 느슨하게 연결

💬 Review Points

  • 현재 주문이 생성되면 데이터 플랫폼에 주문생성 메세지를 전송하고 있습니다. 그런데 나중에 결제가 실패하면 주문을 취소하고, 데이터 플랫폼에 주문 취소 메세지를 추가로 전송하도록 했습니다. 결과 같은 주문 아이디에 두개의 다른 메세지값이 존재하게 됩니다. (주문 생성, 주문 취소) 그럼 같은 주문 아이디에 다른 상황(결제실패)이 발생된다면 이전 메세지는 삭제하거나 덮어쓰기 이런 방식을 도입해야할까요? 그렇다면 이벤트끼리의 순서를 알아야할텐데 이를 위해 메세지큐를 도입해야할까요?
예시입니다..!
- { type: "ORDER_CREATED", orderId: 123, timestamp: "10:00:00" }
- { type: "ORDER_CANCELLED", orderId: 123, timestamp: "10:00:05" }

✅ Checklist

🧾 주문 ↔ 결제

  • 이벤트 기반으로 주문 트랜잭션과 쿠폰 사용 처리를 분리한다.
  • 이벤트 기반으로 결제 결과에 따른 주문 처리를 분리한다.
  • 이벤트 기반으로 주문, 결제의 결과에 대한 데이터 플랫폼에 전송하는 후속처리를 진행한다.

❤️ 좋아요 ↔ 집계

  • 이벤트 기반으로 좋아요 처리와 집계를 분리한다.
  • 집계 로직의 성공/실패와 상관 없이, 좋아요 처리는 정상적으로 완료되어야 한다.

📽️ 공통

  • 이벤트 기반으로 유저의 행동 에 대해 서버 레벨에서 로깅하고, 추적할 방법을 고민해 봅니다.

    상품 조회, 클릭, 좋아요, 주문 등

  • 동작의 주체를 적절하게 분리하고, 트랜잭션 간의 연관관계를 고민해 봅니다.

@rnqhstmd rnqhstmd self-assigned this Dec 12, 2025
@rnqhstmd rnqhstmd added the enhancement New feature or request label Dec 12, 2025
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Dec 12, 2025

Important

Review skipped

More than 25% of the files skipped due to max files limit. The review is being skipped to prevent a low-quality review.

39 files out of 146 files are above the max files limit of 100. Please upgrade to Pro plan to get higher limits.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@looper88888
Copy link
Copy Markdown
Contributor

🧾 주문 ↔ 결제

  • 이벤트 기반으로 주문 트랜잭션과 쿠폰 사용 처리를 분리한다.
  • 이벤트 기반으로 결제 결과에 따른 주문 처리를 분리한다.
  • 이벤트 기반으로 주문, 결제의 결과에 대한 데이터 플랫폼에 전송하는 후속처리를 진행한다.

❤️ 좋아요 ↔ 집계

  • 이벤트 기반으로 좋아요 처리와 집계를 분리한다.
  • 집계 로직의 성공/실패와 상관 없이, 좋아요 처리는 정상적으로 완료되어야 한다.

📽️ 공통

  • 이벤트 기반으로 유저의 행동 에 대해 서버 레벨에서 로깅하고, 추적할 방법을 고민해 봅니다.

    상품 조회, 클릭, 좋아요, 주문 등

  • 동작의 주체를 적절하게 분리하고, 트랜잭션 간의 연관관계를 고민해 봅니다.

@coderabbitai 위 체크리스트에 맞게 개발되었는지 체크해줘

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Dec 13, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

# Find all event classes
echo "=== Event Classes ==="
fd -e java -x grep -l "Event" {} \; | head -20

# Find event listeners
echo -e "\n=== Event Listeners ==="
fd -e java -x grep -l "@EventListener\|@TransactionalEventListener" {} \; | head -20

# Find event publishers
echo -e "\n=== Event Publishers ==="
fd -e java -x grep -l "ApplicationEventPublisher\|publishEvent" {} \; | head -20

# Find order and payment related event files
echo -e "\n=== Order/Payment Event Files ==="
fd -e java | rg -i "order.*event|payment.*event"

# Find like related event files
echo -e "\n=== Like Event Files ==="
fd -e java | rg -i "like.*event"

Length of output: 3422


🏁 Script executed:

#!/bin/bash

# Read Order event and listener
echo "=== OrderCreatedEvent.java ==="
cat apps/commerce-api/src/main/java/com/loopers/domain/order/OrderCreatedEvent.java

echo -e "\n=== OrderEventListener.java ==="
cat apps/commerce-api/src/main/java/com/loopers/interfaces/api/listener/OrderEventListener.java

# Read Payment events and listener
echo -e "\n=== PaymentSucceededEvent.java ==="
cat apps/commerce-api/src/main/java/com/loopers/domain/payment/event/PaymentSucceededEvent.java

echo -e "\n=== PaymentFailedEvent.java ==="
cat apps/commerce-api/src/main/java/com/loopers/domain/payment/event/PaymentFailedEvent.java

echo -e "\n=== PaymentEventListener.java ==="
cat apps/commerce-api/src/main/java/com/loopers/interfaces/api/listener/PaymentEventListener.java

Length of output: 10922


🏁 Script executed:

#!/bin/bash

# Read Like event and listener
echo "=== LikeEvent.java ==="
cat apps/commerce-api/src/main/java/com/loopers/domain/like/LikeEvent.java

echo -e "\n=== LikeEventListener.java ==="
cat apps/commerce-api/src/main/java/com/loopers/interfaces/api/listener/LikeEventListener.java

# Read User Action event and listener
echo -e "\n=== UserActionEvent.java ==="
cat apps/commerce-api/src/main/java/com/loopers/domain/user/UserActionEvent.java

echo -e "\n=== UserActionEventListener.java ==="
cat apps/commerce-api/src/main/java/com/loopers/interfaces/api/listener/UserActionEventListener.java

Length of output: 8391


🏁 Script executed:

#!/bin/bash

# Check how events are published from facades
echo "=== OrderFacade.java ==="
cat apps/commerce-api/src/main/java/com/loopers/application/order/OrderFacade.java

echo -e "\n=== PaymentFacade.java (relevant parts) ==="
cat apps/commerce-api/src/main/java/com/loopers/application/payment/PaymentFacade.java | head -100

echo -e "\n=== PaymentCallbackService.java ==="
cat apps/commerce-api/src/main/java/com/loopers/application/payment/PaymentCallbackService.java

Length of output: 13893


🏁 Script executed:

#!/bin/bash

# Check LikeFacade to verify event publishing
echo "=== LikeFacade.java ==="
cat apps/commerce-api/src/main/java/com/loopers/application/like/LikeFacade.java

# Check ProductFacade for user action tracking
echo -e "\n=== ProductFacade.java ==="
cat apps/commerce-api/src/main/java/com/loopers/application/product/ProductFacade.java

Length of output: 4800


@looper88888 체크리스트를 검증한 결과를 공유드립니다! 🎉

✅ 검증 결과: 모든 항목 구현 완료

🧾 주문 ↔ 결제

  • 이벤트 기반으로 주문 트랜잭션과 쿠폰 사용 처리를 분리

    • OrderFacade.createOrder()에서 주문 생성 후 OrderCreatedEvent 발행
    • OrderEventListener.handleCouponUsage()에서 @TransactionalEventListener(AFTER_COMMIT) + REQUIRES_NEW로 쿠폰 사용 처리
  • 이벤트 기반으로 결제 결과에 따른 주문 처리를 분리

    • PaymentCallbackService에서 결제 성공 시 PaymentSucceededEvent, 실패 시 PaymentFailedEvent 발행
    • PaymentEventListener에서 결제 성공 → 주문 완료, 결제 실패 → 보상 트랜잭션 (재고/쿠폰 복구, 주문 취소)
  • 이벤트 기반으로 주문, 결제의 결과에 대한 데이터 플랫폼 전송

    • OrderEventListener.handleDataPlatformSend(): 주문 생성 메시지
    • PaymentEventListener.handleOrderCompletion(): 주문 완료 메시지
    • PaymentEventListener.handlePaymentFailedCompensation(): 주문 취소 메시지
    • PaymentEventListener.handlePaymentSuccess/FailedDataPlatform(): 결제 성공/실패 메시지

❤️ 좋아요 ↔ 집계

  • 이벤트 기반으로 좋아요 처리와 집계를 분리

    • LikeFacade에서 좋아요 등록/취소 후 LikeEvent 발행
    • LikeEventListener.handleLikeCountUpdate()에서 @TransactionalEventListener(AFTER_COMMIT) + REQUIRES_NEW로 집계 업데이트
  • 집계 로직의 성공/실패와 상관 없이, 좋아요 처리는 정상적으로 완료

    • @Async + AFTER_COMMIT으로 메인 트랜잭션과 완전히 분리
    • 리스너 메서드에서 try-catch로 예외 처리하여 집계 실패해도 좋아요는 정상 완료

📽️ 공통

  • 이벤트 기반으로 유저의 행동을 서버 레벨에서 로깅하고 추적

    • UserActionEvent 정의 (상품 조회, 좋아요, 주문, 결제 등 8가지 액션 타입)
    • ProductFacade: 상품 조회 이벤트
    • LikeEventListener: 좋아요/취소 이벤트
    • OrderEventListener: 주문 생성 이벤트
    • PaymentEventListener: 결제 성공/실패 이벤트
    • UserActionEventListener가 모든 유저 행동 이벤트를 통합 처리하여 데이터 플랫폼으로 전송
  • 동작의 주체를 적절하게 분리하고, 트랜잭션 간의 연관관계 고민

    • 핵심 비즈니스 로직 (주문, 결제, 재고)과 부가 기능 (로깅, 집계, 데이터 전송) 완전 분리
    • @TransactionalEventListener(AFTER_COMMIT): 메인 트랜잭션 커밋 후 실행 보장
    • Propagation.REQUIRES_NEW: 독립적인 트랜잭션으로 실행
    • @Async: 비동기 처리로 성능 향상

🎯 추가로 발견한 우수 구현 사항

  1. 멱등성 보장: 이미 처리된 주문/결제는 스킵하여 중복 처리 방지
  2. 예외 처리: 모든 리스너에서 try-catch로 안전하게 처리
  3. 로깅: 각 단계마다 명확한 로그 메시지로 추적 가능
  4. 캐시 무효화: 좋아요 이벤트 시 관련 캐시 자동 무효화

모든 체크리스트가 완벽하게 구현되었습니다! 👏

@rnqhstmd
Copy link
Copy Markdown
Collaborator Author

@coderabbitai 이번에 커밋한 부분에 대해서 코드 리뷰 남겨줘

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Dec 14, 2025

@rnqhstmd 네, 이번 커밋에 대한 코드 리뷰를 진행하겠습니다! 이벤트 기반 아키텍처로 전환한 주문-결제 플로우, 좋아요-집계 분리, 그리고 유저 액션 추적 구현을 중심으로 상세히 검토해드리겠습니다. 🔍

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@rnqhstmd rnqhstmd closed this Dec 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants