결제 시스템에서 결제를 검증하는 트랜잭션과 웹훅을 저장하는 트랜잭션을 분리했을 때, 웹훅 저장 트랜잭션이 실패할 경우 보상 트랜잭션이 필요한가?
웹훅 저장은 결제 완료의 핵심 로직이 아니라 결제 사실을 기록하는 로그성 작업이기 때문에, 보상 트랜잭션이 아닌 재시도 로직으로 처리하는 것이 적합하다.
처음에는 보상 트랜잭션을 "코드 실행으로 변경된 데이터를 실행 이전 상태로 되돌리는 것", 즉 일반적인 롤백과 같은 개념으로 이해했다.
하지만 일반적인 트랜잭션 롤백은 DB가 자동으로 처리한다.
트랜잭션 시작
├── 포인트 차감
├── 재고 감소
└── 주문 저장 ← 실패!
→ DB가 위 작업들을 전부 자동으로 롤백
보상 트랜잭션은 DB 트랜잭션 범위 밖에 있는 외부 시스템의 작업을 되돌리기 위해 개발자가 직접 작성하는 역방향 로직이다.
대표적인 예가 PG사 결제 승인이다. PG사 API 호출은 DB 트랜잭션과 무관한 외부 시스템이기 때문에, DB 롤백이 일어나도 이미 승인된 결제는 자동으로 취소되지 않는다.
트랜잭션 시작
├── 포인트 차감
├── 재고 감소
├── PG사 결제 승인 API 호출 ← DB 밖, 자동 롤백 불가
└── 주문 저장 ← 실패!→ DB 작업(포인트, 재고, 주문)은 자동 롤백
→ PG사 결제는 이미 승인 완료 → 직접 취소 API 호출 필요 = 보상 트랜잭션
그렇다면 모든 외부 시스템에 보상 트랜잭션이 필요한 것 일까? 답은 아니다. 되돌릴 수 있는 작업인지가 핵심 기준이다.
| 작업 | 보상 |
|---|---|
| PG사 결제 승인 | 필요 (취소 API 존재) |
| 포인트 차감 (외부 서버) | 필요 (복구 API 존재) |
| 이메일/SMS 발송 | 불필요 (되돌릴 수 없음) |
| 웹훅 저장 (로그성) | 불필요 (재시도로 처리) |