개발/axon framework

[axon] event upcasting - clone coding

방푸린 2022. 2. 4. 16:02
반응형

이전 글:

2022.01.25 - [개발/spring] - [axon] query/replay 성능개선 - clone coding

 

[axon] query/replay 성능개선 - clone coding

이전 글: 2022.01.24 - [개발/spring] - [axon] query/replay - clone coding [axon] query/replay - clone coding 2022.01.19 - [개발/spring] - [axon] state stored aggregate - clone coding [axon] state sto..

bangpurin.tistory.com

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

 

14. Query 어플리케이션 구현(Event) - 4

1. 서론 Software 개발 및 유지보수 단계에서 요구사항에 의하여 데이터 모델은 변하기 마련입니다. 그리고 바뀌는 데이터모델에 맞춰 Event 또한 형태가 변합니다. 이때, 이전 발행된 Event와 앞으로

cla9.tistory.com

 

entity -> event의 항목이 바뀌어서 event 모델의 혼용이 생길 경우(ex. replay) 구 -> 신 모델을 어떻게 반영해야 할지에 대해 코드에 알려줘야 할 필요가 있다. 이번 장은 그런 것에 관한 내용이다.

event versioning 이라고 불리는 이 행위는 axon에서는 event upcasting 이라는 용어로 불린다.

 

위 블로그를 참고로 개발하던 와중 필요한 dependency 가 있었다. xml 분석을 위한 라이브러리를 추가해준다.

implementation 'org.dom4j:dom4j:2.1.3'

 

테스트: 아래와 같이 company가 있는 정보로 호출하였다.

POST http://localhost:8080/holder
{
  "holderName" : "ch13",
  "tel" : "02-1234-5678",
  "address" : "OO시 OO구 heheqq",
  "company" : "konai"
}

 

1. command application

DEBUG 8895 --- [mandProcessor-1] c.c.command.aggregate.HolderAggregate    : handling HolderCreationCommand(holderID=e5775054-4265-46ef-8116-297ac22f480d, holderName=ch13, tel=02-1234-5678, address=OO시 OO구 heheqq, company=konai)
...
Hibernate: insert into holder (address, company, holder_name, tel, holder_id) values (?, ?, ?, ?, ?)

command

DB에 잘 들어간 것 확인

2. query application

DEBUG 8893 --- [sor[accounts]-1] c.c.q.p.HolderAccountProjection          : >>> projecting HolderCreationEvent(holderID=e5775054-4265-46ef-8116-297ac22f480d, holderName=ch13, tel=02-1234-5678, address=OO시 OO구 heheqq, company=konai) , timestamp : 2022-02-03T06:52:26.203Z
...
Hibernate: insert into mv_account (account_cnt, address, name, tel, total_balance, holder_id) values (?, ?, ?, ?, ?, ?)

HolderAccountSummary 클래스에 company를 추가한 것은 아니라서 mv_account 테이블에 projection 할 때 추가로 넣는건 없다.

 

3. replay 실행

replay를 실행하는데 문제가 생겼다.. repository를 못 찾아 nullPointException이 뜬 것이다..

di not found...

@Component
@RequiredArgsConstructor
@Slf4j
@ProcessingGroup("accounts")
@EnableRetry
public class HolderAccountProjection {
    private final AccountRepository repository;

...

    @EventHandler
    @AllowReplay
    protected void on(DepositMoneyEvent event, @Timestamp Instant instant){
        log.debug(">>> projecting {} , timestamp : {}", event, instant.toString());
        HolderAccountSummary holderAccount = getHolderAccountSummary(event.getHolderID());
        holderAccount.setTotalBalance(holderAccount.getTotalBalance() + event.getAmount());
        repository.save(holderAccount);
    }

...

    /**
     * 초기화 할 때 실행하는 부분
     */
    @ResetHandler
    private void resetHolderAccountInfo(){
        log.debug("reset triggered");
        repository.deleteAll();
    }

소스는 위와 같은데, 특이한 것은

  1. on 함수는 아무 문제 없이 실행된다(save 가능)
  2. @EnableRetry 어노테이션을 주석처리하면 reset도 에러없이 실행된다....
  3. on 함수 처럼 AllowReplay / DisallowReplay 어노테이션 등등을 넣어봤는데도 똑같다.

뭔가 ResetHandler랑 충돌난게 아닐까.. spring retry를 좀 더 파봐야 겠다..

++++ 해결... 왜인지는 아직 모르겠지만 public 함수로 바꾸니 정상적으로 된다... 공식문서 예시에는 모든 함수가 public으로 되어있긴 한데, 필수는 아닌 것 같은데.... 더 확인이 필요하다.

@ResetHandler
public void resetHolderAccountInfo(){
    log.debug("reset triggered");
    repository.deleteAll();
}

우선 enable retry 를 주석처리한 후 실행해본다. 

upcast bean(eventUpcasterChain 함수)을 등록 하기 전에 한 번, 후에 한 번 해보았다.

upcast bean 등록 전
DEBUG 9935 --- [sor[accounts]-0] c.c.q.p.HolderAccountProjection  : >>> projecting HolderCreationEvent(holderID=65cc77b7-6820-472d-ba72-dd942f801f21, holderName=melvin, tel=02-1234-5678, address=OO시 OO구 hehe, company=null) , timestamp : 2022-01-19T04:23:43.806Z
revision 1.0 version up
DEBUG 9935 --- [sor[accounts]-0] c.c.q.p.HolderAccountProjection  : >>> projecting HolderCreationEvent(holderID=4cafc63c-cdcb-4acf-8943-8dee7492383b, holderName=ch13, tel=02-1234-5678, address=OO시 OO구 heheqq, company=null) , timestamp : 2022-02-03T06:50:28.748Z
DEBUG 9935 --- [sor[accounts]-0] c.c.q.p.HolderAccountProjection  : >>> projecting HolderCreationEvent(holderID=e5775054-4265-46ef-8116-297ac22f480d, holderName=ch13, tel=02-1234-5678, address=OO시 OO구 heheqq, company=konai) , timestamp : 2022-02-03T06:52:26.203Z

upcast bean 등록 후
DEBUG 10126 --- [sor[accounts]-1] c.c.q.p.HolderAccountProjection  : >>> projecting HolderCreationEvent(holderID=65cc77b7-6820-472d-ba72-dd942f801f21, holderName=melvin, tel=02-1234-5678, address=OO시 OO구 hehe, company=N/A) , timestamp : 2022-01-19T04:23:43.806Z
revision 1.0 version up
DEBUG 10126 --- [sor[accounts]-1] c.c.q.p.HolderAccountProjection  : >>> projecting HolderCreationEvent(holderID=4cafc63c-cdcb-4acf-8943-8dee7492383b, holderName=ch13, tel=02-1234-5678, address=OO시 OO구 heheqq, company=null) , timestamp : 2022-02-03T06:50:28.748Z
DEBUG 10126 --- [sor[accounts]-1] c.c.q.p.HolderAccountProjection  : >>> projecting HolderCreationEvent(holderID=e5775054-4265-46ef-8116-297ac22f480d, holderName=ch13, tel=02-1234-5678, address=OO시 OO구 heheqq, company=konai) , timestamp : 2022-02-03T06:52:26.203Z

확인사항

  • 빈 등록 전에는 version up 전의 company 정보가 null로 나온다.
  • 빈 등록 후에는 version up 전의 company 정보가 N/A로 나온다.
  • event version up 후 실수로 company 정보를 넣지 않고 post api 를 요청했는데, 빈 등록 전/후 모두 null로 나왔다. 버전 업을 하고 나서 null로 보냈기 때문에 빈의 유무와 상관없이 null로 나오는 것이 맞다.

 


참고: event upcasting 원문, 기타 의미: https://docs.axoniq.io/reference-guide/axon-framework/events/event-versioning

 

Event Versioning - Axon Reference Guide

Axon's upcasters do not work with the EventMessage directly, but with an IntermediateEventRepresentation. The IntermediateEventRepresentation provides functionality to retrieve all necessary fields to construct an EventMessage (and thus a upcasted EventMes

docs.axoniq.io

 

728x90
반응형