이전 글: 2022.02.18 - [개발/spring] - [axon] saga (1) - clone coding
클론 코딩 참고 블로그는 다음과 같다: https://cla9.tistory.com/24?category=814447
Saga 트랜잭션에서 실패가 났을 경우 recovery 하는 방법에 대한 글이다. 딱히 신기술이나 신개념이 나오는 것은 아니고 exception을 try/catch 문으로 잡아서 catch문에서 새로운 이벤트를 전파시켜 롤백하는 과정이다. 즉, 로직적으로 해결하는 것이라서 흐름만 잘 따라가면 된다.
해당 글에서는 두 가지 케이스에 대해 다룬다.
- 타임아웃으로 인한 잔액 복구 케이스
- 타임아웃이 났는데 어차피 잔액이 모자라서 진행이 안 되는 케이스(하지만 진행을 했다가 취소하는 방식으로 진행한다; 이벤트는 삭제할 수 없기 때문에 취소 이벤트를 발생해줘야 한다)
각 흐름에 대해 정리한다. 소스를 보면서 따라가야 하며 로그를 같이 보면 훨씬 빠르게 접근할 수 있다.
소스는 역시 깃허브에..
- 타임아웃으로 인한 잔액 복구 케이스
중간에 요청 없어짐 표시는 무시해도 된다. 처음에 테스트할 때 잔액 차감 성공 이벤트가 로그에 찍혔는데, 잔액을 복구하는 로직이 없어서 이상하다 싶었는데 다시 확인해보니, 잔액 차감 성공(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 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 |