Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

결제 → 송금 플로우 이벤트 적용 #30

Merged
merged 3 commits into from
Feb 11, 2025

Conversation

jaeyeong951
Copy link
Collaborator

@jaeyeong951 jaeyeong951 commented Jan 29, 2025

🌱 관련 이슈

  • close #

📌 작업 내용 및 특이 사항

  • 결제 > 송금 플로우에 modulith 이벤트를 적용하였습니다.
    • 결제 시 결제 이력만 저장 후 '결제됨' 이벤트를 발행합니다.
    • 송금 모듈에서 해당 이벤트를 수신하여 계좌이체 & 송금 이력 저장을 수행합니다.
    • 송금 모듈에서 오류 발생 시 '결제실패' 이벤트를 발행합니다.
    • 결제 모듈에서 이를 수신하여 해당 결제를 원복합니다.

📝 참고

  • modulith 이벤트를 사용하면 DB 에 아래와 같은 형식의 테이블이 하나 만들어집니다.
-- auto-generated definition
create table event_publication
(
    completion_date  timestamp(6) with time zone,
    publication_date timestamp(6) with time zone,
    id               uuid not null
        primary key,
    event_type       varchar(255),
    listener_id      varchar(255),
    serialized_event varchar(255)
);
image
  • 이벤트를 발행할 때 최초 저장 후 수신할 때 다시 update 가 자동으로 이루어집니다. (로그를 켜면 insert, update 동작이 모두 보여요)
  • 일단 제 생각으로는 단순히 이벤트 로깅용 테이블로 보입니다. (이벤트가 잘 발행되었고 잘 수신되었는지)
  • 처음에는 transactional outbox 패턴에 활용하라고 만든건가?! 했는데 다시 보니 그 용도론 못쓰겠다 싶더라구요.
  • 기본적으로 findIncompletePublications() 같은 조회 메소드를 modulith 에서 기본적으로 제공을 해주기는 해요. (아직 처리안된 이벤트 조회)
  • 굳이 굳이 outbox 패턴으로 쓰려면 이벤트 발행만 하고 아무 동작도 안하도록 만들어야하는데 (이벤트 발행은 순전히 outbox 테이블에 row 저장하는 용도가 되어버림) 이렇게 쓸 바에야 그냥 outbox 테이블 만들고 말 것 같네요.

📚 기타

  • 사실 SAGA 라고 부르기는 민망할 정도로 간단하게 구현했습니다 ㅎㅎ..
  • 자세히 따지고 보면 허점이 너무 많아요.
  • 그래도 우리는 modulith 잘 쓰기가 목적이니 구현 상 허점은 흐린눈을 조금 해야겠습니다

@jaeyeong951 jaeyeong951 self-assigned this Jan 29, 2025
@jaeyeong951 jaeyeong951 added the code 코드 label Jan 29, 2025
@devFancy devFancy added the tech 기술 경험 label Jan 29, 2025
Comment on lines +5 to +9

class PaymentCompletedEvent(
val paymentId: Long,
val amount: BigDecimal,
) : DomainEvent()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

amount값도 추가하여 Event 객체 생성 좋습니다! 👍

Comment on lines +19 to +32
fun handle(event: PaymentCompletedEvent) {
try {
// FIXME account 조회 로직 필요
val sourceAccount: Account
val destinationAccount: Account
val transferResult =
externalBankTransferApi
.transfer(
sourceAccountNumber = sourceAccount.accountNumber,
destinationAccountNumber = destinationAccount.accountNumber,
amount = event.amount.toLong(),
).result
if (transferResult.not()) eventPublisher.publishEvent(PaymentFailedEvent(paymentId = event.paymentId))
transferRepository.save(Transfer(transferResult))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

transferResult의 타입은 boolean으로 return 되는 것으로 보이는데 Transfer 객체 인자로 boolean을 넣으면 어떻게 되나요?!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아 해당 부분은 아직 Transfer 모듈쪽이 구현이 안되어서 있어서 살짝 pseudo 코드 느낌으로 넣은건데요, 추후 송금 클래스가 만들어지면 송금 결과 필드가 필요하지 않을까? 해서 일단 저렇게 transferResult 를 넣어놨어요.
송금 클래스 완성 후에는 수정되어야합니다!

Copy link
Member

@char-yb char-yb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 확인했습니다!
LGTM~

Copy link
Member

@devFancy devFancy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

구현해주시느라 정말 고생하많으셨어요 ! 👍👍
결제 모듈에서 결제 이력을 저장하고 해당 부분을 이벤트로 저장한 부분을 추가해주셔서 감사해요 !

코드를 보면서 몇 가지 질문이 있어서 아래에 남겼어요 ~

  • 결제를 처리하는 API (/payment/request/)의 비즈니스 로직에서 결제 이력을 저장한 뒤에 이벤트로 저장한 부분까지 확인했습니다. 이 부분은 지갑에 대한 차감에 해당되는게 맞고(결제 - 지갑), 재영님이 올리신 부분과 다른 내용이 맞으실까요? 결제 - 송금 아니면 결제 - 지갑 이후의 로직이 송금인걸까요?

  • compensatePayment 는 결제 처리에 대한 실패와 관련된 로직을 의미하는게 맞을까요? 결제 상태를 FAILED 라고 적혀져 있어서요. 🙂 제가 이해하기로는 재영님이 작성해주신 결제 > 송금 플로우의 마지막 부분인 결제 모듈에서 이를 수신하여 해당 결제를 원복합니다. <-- 이 부분인 것 같아서요!

  • TransferEventListener 클래스에 handle 메소드에 모놀리스 관련 어노테이션인 @ApplicationModuleListener 를 적용하셨는데, 내부에 어노테이션인 @TransactionalEventListener이 있던데, 이는 기본값으로 AFTER_COMMIT 을 사용하는데, 해당 부분을 생각해서 적용하신게 맞으실까요?

    • AFTER_COMMIT - 트랜잭션이 성공적으로 완료된 후 이벤트를 실행

귀찮게 해드려서 미리 죄송드리고, 혹여나 제가 이해한 부분과 다른 것 같아서 질문을 남기게 되었어요 🙏🏻

Comment on lines +18 to +19
@ApplicationModuleListener
fun handle(event: PaymentCompletedEvent) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator Author

@jaeyeong951 jaeyeong951 Jan 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@devFancy
준용님 세세하게 봐주셔서 감사합니다! (이런 질문들 전혀 귀찮지 않아요🥺)
질문주신 것에 대한 제 생각 말씀드릴게요.

  1. 결제라는 동작에서 결제 모듈과 송금 모듈의 역항에 대해 제가 이해한 바는 아래와 같습니다.

결제 모듈은 아래 동작을 수행하구요

  • 지갑 차감
  • 결제 이력 저장
  • 결제 완료 이벤트 발행
  • 결제 실패 이벤트 수신

송금 모듈은 아래 동작을 수행합니다.

  • 결제 완료 이벤트 수신
  • 계좌 송금
  • 송금 이력 저장
  • 송금 실패 시 결제 실패 이벤트 발행
  1. 결제를 원복했다는 건 결국 결제의 실패라고 봤어요.

  2. 네~ 맞습니다 같은 애플리케이션 내부 모듈간의 통신이긴 하지만 외부 이벤트 브로커를 통하는 것 처럼 쓰라고 만든게 ApplicationModuleListener 라고 이해했어요

@char-yb
Copy link
Member

char-yb commented Jan 31, 2025

@devFancy
AFTER_COMMIT이 맞지 않을까요?.?
현재 송금 이력에 대한 이벤트 발급 처리 시 try를 통해 정상적으로 커밋이 되면 발행이 되어주고
에러 발생 시 catch에서 재영님이 별도 event 발행 처리를 해둔 것으로 보여요!

Copy link
Member

@devFancy devFancy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

답변 감사합니다 재영님! 🙌🏻
변화된 도메인 구조에 맞게 이벤트 스토밍도 수정해야할 것 같은데, 이 부분은 2차 미션 이후에 다시 한번 회의를 해봐야겠네요.

고생많으셨어요 ! 👍👍

@devFancy
Copy link
Member

@devFancy AFTER_COMMIT이 맞지 않을까요?.? 현재 송금 이력에 대한 이벤트 발급 처리 시 try를 통해 정상적으로 커밋이 되면 발행이 되어주고 에러 발생 시 catch에서 재영님이 별도 event 발행 처리를 해둔 것으로 보여요!

넵넵! 저도 그렇게 생각했어요 ~ 추가 설명 감사드려요 !

@jaeyeong951
Copy link
Collaborator Author

다들 세심한 리뷰 감사합니다! 코드 작성하던 시점이 계좌 모듈 구현 전이라 계좌 도메인을 참조하는 부분은 대부분 mock 으로 구현되어있는데요, 계좌 모듈과 통합은 추후 별도 PR 로 올리는게 좋을 것 같습니다!

@jaeyeong951 jaeyeong951 merged commit 42a6b11 into develop Feb 11, 2025
@jaeyeong951 jaeyeong951 deleted the week5/jaeyeong-payment-event branch February 11, 2025 16:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
code 코드 tech 기술 경험
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants