Saga 패턴

Saga는 성공한 로컬 커밋만 역순 보상한다

여러 서비스가 하나의 ACID 트랜잭션으로 묶이지 않을 때, 각 단계는 자기 DB에 먼저 커밋한다. 중간 실패가 나면 DB 롤백이 아니라 이미 성공한 업무를 반대 의미의 새 명령으로 되돌린다.

01 주문 생성 커밋 Order DB에 주문 식별자와 대기 상태를 확정한다.
02 재고 예약 커밋 Inventory DB에 예약 수량과 reservationId를 남긴다.
03 결제 실패 지점 Payment 단계에서 실패를 기록하고 진행을 멈춘다.
C1 역순 보상 시작 성공한 재고 예약부터 반대 명령으로 되돌린다.

결제 실패 후 보상 스택이 만들어지는 순간

예: 주문 생성과 재고 예약은 이미 커밋됐고, 결제 승인에서 영구 실패가 난 상황이다.

정방향
로컬 트랜잭션
01 주문 생성 커밋

Order DB에 PENDING_ORDER와 orderId를 저장한다.

02 재고 예약 커밋

Inventory DB에 reservationId와 예약 수량을 남긴다.

03 결제 승인 실패

영구 실패면 다음 성공 단계로 가지 않고 보상으로 전환한다.

saga_state 성공한 단계만 보상 대상이 된다.
completed order_created, stock_reserved
failed_at payment_authorize
next compensation release_reservation
final state CANCELLED 또는 COMPENSATED
역순
보상 트랜잭션
C1 예약 해제

reservationId 기준으로 재고 예약을 한 번만 해제한다.

C2 주문 취소

orderId 상태를 CANCELLED로 전이하고 취소 이벤트를 남긴다.

END 운영 관측

보상 완료, 실패, 재시도 대기 상태를 대시보드에 노출한다.

보상 명령 롤백이 아니라 새 업무 작업

재고 예약 해제, 주문 취소처럼 도메인 의미가 반대인 명령을 별도로 구현한다.

멱등성 보상도 여러 번 도착할 수 있다

commandId와 처리 이력으로 중복 이벤트와 오케스트레이터 재시작을 견딘다.

중간 상태 사용자에게 진행 중을 숨기지 않는다

PROCESSING, COMPENSATING, FAILED처럼 원자적 커밋 사이의 상태를 명확히 표시한다.