본문 바로가기

DDD 10장 이벤트

DDD 10장 이벤트

이벤트

  • 이벤트의 용도와 장점
  • 핸들러 디스패치와 핸들러 구현
  • 비동기 이벤트 처리

 

주문을 취소 후 환불 처리하는 과정은?

주문 취소 + 환불 처리

 

결제 시스템은 외부에 존재하므로 외부의 환불 시스템 서비스를 호출하는데 문제가 2가지 있음.

  1. 외부 서비스가 정상이 아닐 경우 트랜잭션 처리를 어떻게 할 것인가?

Q. 환불 기능을 실행하는 과정에서 익셉션이 발생했다면, 트랜잭션 롤백을 해야 할까? 커밋을 해야 할까?

외부의 환불 서비스를 실행하는 과정에서 익셉션이 발생하면 환불에 실패했으므로 주문 취소 트랜잭션을 롤백 하는 것이 맞는 것으로 보인다.

하지만, 반드시 트랜잭션을 롤백해야 하는 것은 아니다. 주문은 취소 상태로 변경하고 환불만 나중에 다시 시도하는 방식으로 처리할 수도 있다.

  1. 성능에 대한 것.

환불을 처리하는 외부 시스템의 응답 시간이 길어질수록 대기 시간이 발생.

외부 서비스 성능에 직접적인 영향을 받는 문제 발생.

  1. 도매인 객체에 서비스를 전달하면 추가로 설계상 문제가 나타날 수 있음.

주문 로직과 결제 로직이 섞이는 문제.

 

문제가 발생하는 이유

주문 BOUNDED CONTEXT와 결제 BOUNDED CONTEXT 간의 강결합(high coupling) 때문.

-> 이런 강한 결합을 없애는 방법이 이벤트를 사용!!!!

-> 비동기 이벤트를 사용하면 두 시스템 간의 결합을 크게 낮출 수 있다.

 

이벤트

이벤트(event) : 과거에 벌어진 어떤 것.

이벤트가 발생했다는 것은 상태가 변경됐다는 것을 의미.

이벤트 관련 구성 요소

이벤트 생성 주체 : 도메인 모델에서 이벤트 주체는 엔티티, 밸류, 도메인 서비스와 같은 도메인 객체이다. 이들 도메인 객체는 도메인 로직을 실행해서 상태가 바뀌면 관련 이벤트를 발생한다.

이벤트 디스패처(이벤트 퍼블리셔) : 이벤트 생성 주체와 이벤트 핸들러를 연결해 주는 것이 이벤트 디스패처이다.

이벤트 핸들러(이벤트 구독자) : 이벤트 생성 주체가 발생한 이벤트에 반응한다. 이벤트 핸들러는 생성 주체가 발생한 이벤트를 전달 받아 이벤트에 담긴 데이터를 이용해서 원하는 기능을 실행한다.

  • 이벤트는 현재 기준으로 과거에 벌어진 것을 표현하기 때문에 이벤트 이름에는 과거 시제를 사용한다.
  • 이벤트는 이벤트 핸들러가 작업을 수행하는 데 필요한 최소한의 데이터를 담아야 한다.

 

이벤트의 용도

  1. 트리거

도메인의 상태가 바뀔 때 다른 후처리를 실행하기 위한 트리거로 이벤트 사용

ex) 주문 취소 이벤트 발생 -> 환불 처리 트리거가 됨.

  1. 서로 다른 시스템 간의 데이터 동기화

ex) 배송지 변경 이벤트 발생 -> 이벤트 핸들러 : 외부 배송 서비스와 배송지 정보를 동기화

 

이벤트의 장점

서로 다른 도메인이 섞이는 것을 방지할 수 있음!

 

이벤트, 핸들러, 디스패치 구현

  • 이벤트 클래스

이벤트 자체를 위한 상위 타입 존재하지 않음.

원하는 클래스를 이벤트로 사용.

이벤트는 과거에 벌어진 상태 변화나 사건을 의미하므로 이벤트 클래스의 이름을 결정할 때에는 과거 시제를 사용해야 한다.

이벤트 클래스는 이벤트를 처리하는 데 필요한 최소한의 데이터를 포함해야 한다.

  • EventHandler : 이벤트 핸들러를 위한 상위 타입으로 모든 핸들러는 이 인터페이스를 구현

Handle() 메서드를 이용해서 필요한 기능을 구현.

  • Events : 이벤트 디스패처, 이벤트 발행, 이벤트 핸들러 등록

내부적으로 핸들러 목록을 유지하기 위해 ThreadLocal 사용

끝난후에 Events.reset() 필수 (안하면 메모리 부족 에러 발생)


비동기 이벤트 처리

A하면 이어서 B하라

-> A하면 최대 언제까지 B하라.

-> 이벤트를 비동기로 처리하는 방식으로 구현 가능.

로컬 핸들러를 비동기로 실행하기

이벤트 핸들러를 별도 스레드로 실행하는 것.

메시지 큐를 사용하기

이벤트 발생 -> 이벤트 디스패처는 이벤트를 메시지큐에 보냄 -> 메시지큐는 이벤트를 메시지 리스너에 전달 -> 메시지 리스너는 알맞은 이벤트 핸들러를 이용해서 이벤트를 처리.

많은 경우 메시지 큐를 사용하면 보통 이벤트를 발생하는 주체와 이벤트 핸들러가 별도 프로세스에서 동작한다.

이벤트 저장소와 이벤트 포워더 사용하기

이벤트를 일단 DB에 저장한 뒤에 별도 프로그램을 이용해서 이벤트 핸들러에 전달하는 것.

  1. 포워더

이벤트가 발생하면 핸들러는 스토리지에 이벤트를 저장.

포워더는 주기적으로 이벤트 저장소에서 이벤트를 가져와 이벤트 핸들러를 실행한다.

  1. API 방식

이벤트가 발생하면 핸들러는 스토리지에 이벤트를 저장.

외부 핸들러가 API 서버를 통해 이벤트 목록을 가져오는 방식.