Saga chia một giao dịch phân tán thành chuỗi transaction cục bộ; mỗi bước có một compensating transaction để đảo ngược tác động khi bước sau thất bại. Ví dụ đặt vé: Tạo booking → Giữ chỗ → Trừ tiền. Nếu trừ tiền lỗi thì chạy ngược: Nhả chỗ → Huỷ booking.
Nguyên tắc thiết kế compensation:
- Bù trừ theo ngữ nghĩa, không phải rollback. Đã trừ tiền thì bù bằng một giao dịch hoàn tiền mới, không xoá bản ghi cũ. Đã gửi email thì bù bằng email đính chính — có những tác động không thể hoàn tác, phải chấp nhận và thiết kế nghiệp vụ quanh nó.
- Compensation phải idempotent và retry được. Nó chạy trong tình huống hệ thống đang lỗi, sẽ bị gọi lại nhiều lần.
- Chạy ngược thứ tự các bước đã hoàn tất, và chỉ những bước đã thực sự hoàn tất.
- Giao dịch trung gian có thể bị nhìn thấy. Saga không có isolation: có khoảng thời gian booking tồn tại rồi biến mất. Xử lý bằng trạng thái tường minh (PENDING, CONFIRMED, CANCELLED) để phần còn lại của hệ thống không hiểu nhầm.
Khi chính compensation lỗi — đây là phần thật sự phân loại ứng viên:
1. Retry với backoff, vì phần lớn là lỗi tạm thời.
2. Hết retry thì không được bỏ qua: đẩy vào DLQ và chuyển sang trạng thái COMPENSATION_FAILED, không phải CANCELLED.
3. Cảnh báo cho người — đây là trạng thái không nhất quán cần can thiệp thủ công (tiền đã trừ mà chỗ đã nhả).
4. Job đối soát định kỳ quét các saga treo quá lâu, so khớp với hệ thống thanh toán và báo cáo chênh lệch.
5. Ghi log toàn bộ hành trình saga (mỗi bước, mỗi lần thử, mỗi kết quả) để người xử lý biết cần sửa gì.
Orchestration (một service điều phối, giữ state machine) dễ theo dõi và dễ bù trừ hơn choreography khi chuỗi bước dài, vì trạng thái saga nằm ở một chỗ.