반응형

이전 글: 2022.02.18 - [개발/spring] - [axon] saga (1) - clone coding

 

[axon] saga (1) - clone coding

이전 글: 2022.02.14 - [개발/spring] - [axon] query handler(2) - clone coding 클론 코딩 참고 블로그는 다음과 같다: https://cla9.tistory.com/23?category=814447 19. Saga 패턴을 활용한 트랜잭션 관리 -..

bangpurin.tistory.com

클론 코딩 참고 블로그는 다음과 같다:  https://cla9.tistory.com/24?category=814447 

 

20. Saga 패턴을 활용한 트랜잭션 관리 - 3

1. 서론 이번 포스팅은 AxonFramework 관련 마지막 포스팅입니다. Saga 패턴 보상 트랜잭션 구현을 다루겠습니다. 2. Deadline MSA 환경에서는 App이 여러개로 분산되어있으므로 하나의 App이 느려지거나 장

cla9.tistory.com

 

Saga 트랜잭션에서 실패가 났을 경우 recovery 하는 방법에 대한 글이다. 딱히 신기술이나 신개념이 나오는 것은 아니고 exception을  try/catch 문으로 잡아서 catch문에서 새로운 이벤트를 전파시켜 롤백하는 과정이다. 즉, 로직적으로 해결하는 것이라서 흐름만 잘 따라가면 된다.

해당 글에서는 두 가지 케이스에 대해 다룬다.

  1. 타임아웃으로 인한 잔액 복구 케이스
  2. 타임아웃이 났는데 어차피 잔액이 모자라서 진행이 안 되는 케이스(하지만 진행을 했다가 취소하는 방식으로 진행한다; 이벤트는 삭제할 수 없기 때문에 취소 이벤트를 발생해줘야 한다)

각 흐름에 대해 정리한다. 소스를 보면서 따라가야 하며 로그를 같이 보면 훨씬 빠르게 접근할 수 있다. 

소스는 역시 깃허브에..

 

  • 타임아웃으로 인한 잔액 복구 케이스

중간에 요청 없어짐 표시는 무시해도 된다. 처음에 테스트할 때 잔액 차감 성공 이벤트가 로그에 찍혔는데, 잔액을 복구하는 로직이 없어서 이상하다 싶었는데 다시 확인해보니, 잔액 차감 성공(TransferApprovedCommand) 시 로직이 덜 짜져 있어서(if (!isExecutingCompensation && !isAbortingCompensation)이 부분이 없었다.) 잘못된 코드였고, 수정해서 안 나오는 게 맞다는 것을 확인했다. 즉, 잔액 차감 성공(TransferApprovedCommand) 을 받았지만 취소 중이면 차감을 아애 안 하는 로직인 것임.

괄호의 숫자는 로그의 시간이다. 시간순으로 나열한 것은 아니므로 주의해서 확인해야한다..

특이점은  jeju에서는 잔액이 감소(이체 성공)하고 다시 복구(이체 취소)하는 과정을 거치지만, command 쪽은 아예 잔액 변경이 없다.

--------------------command
commandGateway.sendAndWait(MoneyTransferCommand)
@CommandHandler transferMoney(MoneyTransferCommand)
	AggregateLifecycle.apply(MoneyTransferEvent)
///사가 시작
@StartSaga @SagaEventHandler(associationProperty = "transferID") on(MoneyTransferEvent)
	commandGateway.sendAndWait(JejuBankTransferCommand) (17:01:23.740)
	10초 기다리다 익셉션 (17:01:33.744)
--------------------jeju
@CommandHandler on(JejuBankTransferCommand)
	15초 홀딩하던도중 취소 요청을 받긴하지만 홀딩 후 성공처리 먼저함
	AggregateLifecycle.apply(TransferApprovedEvent) (17:01:38.790)
@EventSourcingHandler on(TransferApprovedEvent)
	잔액 차감 (17:01:38.791)
--------------------command
//요청 없어짐 
//{익셉션 (17:01:33.744)시 isExecutingCompensation = true로 바뀌었고 그 후에 들어온 이체 성공(잔액 차감) 요청이므로 진행 안 됨}
//@SagaEventHandler(associationProperty = "srcAccountID") on(TransferApprovedEvent)
//	제주 잔액 차감 성공 이벤트 리슨 후 반영
//	commandGateway.send(TransferApprovedCommand)
//@CommandHandler transferMoney(TransferApprovedCommand)
//	잔액 증가
//	AggregateLifecycle.apply(DepositMoneyEvent) //for query app
//	AggregateLifecycle.apply(DepositCompletedEvent)// 사가 종료;; 근데 왜 로그 없지?
//요청 없어짐
		
cancelTransfer(17:01:33.744)
	취소 요청
	commandGateway.send(JejuBankCancelTransferCommand)
--------------------jeju
@CommandHandler on(JejuBankCancelTransferCommand)
	취소 요청
	AggregateLifecycle.apply(CompletedCancelTransferEvent) (17:01:38.818)
@EventSourcingHandler on(CompletedCancelTransferEvent) (17:01:38.819)
	잔액 복구 (17:01:38.819)
--------------------command	
@SagaEventHandler(associationProperty = "srcAccountID") on(CompletedCancelTransferEvent)
	계좌이체 취소완료 (17:01:38.854)
///사가 종료

 

  • 타임아웃이 났는데 어차피 잔액이 모자라서 진행이 안 되는 케이스

여기서 특이점은 jeju에서는 잔액이 증가(복구)하고 다시 취소(회수)하는 과정을 거치지만, command쪽은 아애 잔액 변경이 없다. 타임아웃으로 인한 복구가 먼저 진행되고, 잔액이 없어서 이체를 취소하는 요청 시 복구 중인지 확인한 후 복구 중이면 다시 복구를 취소하는 것이다(복구 중이 아니면 그대로 종료).

--------------------command
commandGateway.sendAndWait(MoneyTransferCommand)
@CommandHandler transferMoney(MoneyTransferCommand) (17:34:06.636)
	AggregateLifecycle.apply(MoneyTransferEvent)
///사가 시작
@StartSaga @SagaEventHandler(associationProperty = "transferID") on(MoneyTransferEvent)
	commandGateway.sendAndWait(JejuBankTransferCommand) (17:34:06.708)
	10초 기다리다 익셉션 (17:34:16.715)
cancelTransfer
	취소 요청
	commandGateway.send(JejuBankCancelTransferCommand) (17:34:16.715)
--------------------jeju
@CommandHandler on(JejuBankTransferCommand)
	15초 홀딩하던 도중 취소 요청을 받긴하지만 홀딩 후 성공처리 먼저함
	AggregateLifecycle.apply(TransferDeniedEvent) (17:34:21.832)
@CommandHandler on(JejuBankCancelTransferCommand) (17:34:21.862)
	AggregateLifecycle.apply(CompletedCancelTransferEvent)
@EventSourcingHandler on(CompletedCancelTransferEvent)
	잔액 증가/복구됨 (17:34:21.862)
--------------------command
@SagaEventHandler(associationProperty = "srcAccountID") on(TransferDeniedEvent) (17:34:21.874)
	취소 중이면서 계좌이체도 실패 -> 잔액 복구되면 안됨
	commandGateway.send(JejuBankCompensationCancelCommand) (17:34:21.874)
--------------------jeju
@CommandHandler on(JejuBankCompensationCancelCommand) (17:34:21.896)
	apply(CompletedCompensationCancelEvent)
 @EventSourcingHandler on(CompletedCompensationCancelEvent)
	잔액 다시 감소(17:34:21.900)
--------------------command
@SagaEventHandler(associationProperty = "srcAccountID") @EndSaga on(CompletedCompensationCancelEvent)
	상황 종료 (17:34:21.923)
///사가 종료

 

와 드디어.. axon framework clone coding 20강의 여정이 끝났다. 너무 어렵고 이게 지금 당장 쓰일 수 있을 것 같지 않아서 중간에 그만두고 싶기도 한데, 어쨌든 끝나서 후련하다!!

다음 시간에는 axon framework를 (개인적으로) 총 정리해볼 예정이다.

2022.02.21 - [개발/spring] - [axon] clone coding 후기

 

[axon] clone coding 후기

들어가며.. 마이크로 서비스 아키텍처(MSA) 프로젝트를 개발 및 운영을 하다보면 자연스레 도메인 모델은 복잡해지고 점점 설계 시점의 의도와는 다른 방향으로 변질되는 일이 빈번히 발생한다.

bangpurin.tistory.com

 

728x90
반응형

'개발 > axon framework' 카테고리의 다른 글

[axon] clone coding 후기  (0) 2022.02.21
[axon] saga (1) - clone coding  (0) 2022.02.18
[axon] query handler(2) - clone coding  (0) 2022.02.14
[axon] query handler(1) - clone coding  (0) 2022.02.11
[axon] event upcasting - clone coding  (0) 2022.02.04

+ Recent posts