하나의 @Transactional 에 핵심 로직과 부가 로직을 전부 묶어 두면, 외부 API 지연이 DB 커넥션 점유로 이어져 서비스 전체에 영향을 준다는 것을 배웠다.
"이 로직이 실패하면 주문 자체를 롤백해야 하는가?" 라는 질문 하나로 핵심 트랜잭션과 후속 처리를 나눌 수 있었다.
트랜잭션을 분리한 뒤에는 이벤트 유실 문제가 따라왔기때문에 이걸 해결하기 위해 Transactional Outbox Pattern 을 도입했다.
이런 고민이 있었어요
파티션 키를 누구 기준으로 잡을 것인가의 고민이 있었다. 파티션 키를 이벤트를 생성하는 주체(orderId)가 아니라 상태를 변경하는 대상(productId) 기준으로 잡아야 한다는 점을 깨달았다.
선착순 쿠폰에서 @Transactional 이 동작하지 않는 문제가 있었다. 동시성 테스트에서 발급 수량이 0에서 바뀌지 않았다. 원인은 같은 클래스 내부에서 this.tryIssue() 를 호출하면서 Spring AOP 프록시를 우회한 Self-Invocation 이었다. 트랜잭션 로직을 별도 빈으로 분리해서 외부 호출로 바꾸니 정상적으로 동작하는걸 확인했다.
앞으로 실무에 써먹을 수 있을 것 같은 포인트
Kafka 를 이번 과제를 통해 처음 접했는데 실무에서 Kafka 를 다뤄야 하는 경우가 생겼을때 너무 겁먹지 않아도 될 것같다.
모든 이벤트에 Outbox 를 적용할 필요가 없다는 판단이 생긴것 같다. "이 데이터는 유실을 허용해도 되는가?" 라는 관점으로 트레이드오프 할 수 있는 관점이 생겼다.
아쉬웠던 점 & 다음에 해보고 싶은 것
Kafka 를 이번에 처음 접해봐서 어떻게 어떤 방향을 잡고 과제를 해야하는지 감이 안잡혀서 초반에 회피를 좀 했던것 같다. 결국 부랴부랴 한거같은데.. 일단 그냥 부딪혀보는 습관을 들이는게 좋을 것 같다.