Concert Booking / Engineering case
commit 이후의 실패를 사라진 사건으로 만들지 않기
Outbox는 발행 실패를 DB에 남기고, DLT는 처리 실패를 정상 흐름에서 격리해 다시 시작할 위치를 제공합니다.
GitHub에서 코드 보기 ↗User impact
예약 취소가 완료됐다는 응답 뒤에도 좌석 반환 이벤트가 사라지면 다른 사용자는 계속 좌석을 선택할 수 없습니다.
01
어떻게 깨지는가
- DB commit 직후 process가 종료되면 Kafka 발행 여부를 알 수 없습니다.
- poison message를 무한 재시도하면 정상 이벤트도 함께 막힙니다.
02
지켜야 할 경계
- 도메인 변경과 이벤트 기록 사이에 틈이 없어야 합니다.
- 중복 replay는 허용하되 좌석 재고가 두 번 늘면 안 됩니다.
- 도메인 변경과 Outbox event를 같은 transaction에 기록합니다.
- relay가 발행 실패를 상태와 retry 시각으로 남깁니다.
- consumer 실패는 DLT로 격리한 뒤 원인을 확인하고 replay합니다.
03
선택한 설계
- 도메인 변경과 Outbox insert를 같은 transaction에 묶습니다.
- relay가 실패 횟수와 다음 시각을 기록하고 terminal DEAD 상태를 구분합니다.
- consumer 실패는 DLT에 격리하고 원인을 확인한 뒤 replay합니다.
04
감수한 trade-off
- 즉시 일관성 대신 eventual release를 받아들이고 UI에 반영 중 상태를 표시합니다.
- 운영 상태가 늘지만 실패를 관찰하고 수동 복구할 수 있습니다.
05
어떻게 확인했는가
- 강제 Kafka 실패 뒤 FAILED로 남고 다음 retry에서 PUBLISHED가 됩니다.
- DLT replay를 두 번 실행해도 좌석 반환은 한 번만 반영됩니다.
- 브라우저 E2E에서 취소와 만료 뒤 좌석이 AVAILABLE로 돌아옵니다.
Replay the boundary
글 대신 단계별로 따라보기
Sources
코드와 테스트로 돌아가기
한계와 다음 확인
- exactly-once를 주장하지 않고 중복을 흡수할 상태와 키를 제공합니다.
- 장시간 broker 장애의 운영 복구 시간을 측정하지 않았습니다.