Saga Pattern
Di microservices, satu bisnis proses (misal: buat order) bisa melibatkan banyak service. Saga mengkoordinasi transaksi terdistribusi tanpa 2-phase commit — setiap step punya compensating action untuk rollback.
Choreography vs Orchestration
Choreography (Event-driven)
Setiap service publish event, service lain react.
Order Service → "OrderCreated" event
→ Payment Service listens → charge card → "PaymentCompleted"
→ Inventory Service listens → reserve stock → "StockReserved"
→ Shipping Service listens → create shipment → "ShipmentCreated"
// Jika Payment gagal:
Payment Service → "PaymentFailed" event
→ Order Service listens → cancel order (compensate)
Orchestration (Central coordinator)
Satu orchestrator mengarahkan step-by-step.
class OrderSagaOrchestrator {
async execute(order) {
try {
await paymentService.charge(order);
await inventoryService.reserve(order);
await shippingService.create(order);
} catch (err) {
// Compensate in reverse order
await shippingService.cancel(order);
await inventoryService.release(order);
await paymentService.refund(order);
}
}
}
Kapan Pakai Apa?
- Choreography — Simple sagas (2-3 steps), loose coupling, setiap service independen
- Orchestration — Complex sagas (4+ steps), visibility penting, easier to debug
Challenges
- Idempotency — Compensating actions harus idempotent (bisa dipanggil berkali-kali)
- Ordering — Event bisa datang out of order
- Observability — Tracing saga yang melintasi banyak service
- Partial failure — Apa yang terjadi jika compensating action juga gagal?
🎭 Analogi sehari-hari
Booking liburan: pesan hotel, pesan tiket pesawat, sewa mobil. Kalau sewa mobil gagal, kamu harus undo: cancel hotel + cancel tiket pesawat (kompensasi). Setiap step punya cancel-action yang sesuai. Itulah Saga.
Kalau pakai 2PC: travel agent tahan semua booking sampai semua confirm. Lambat + kalau agent disconnect = booking nya stuck di limbo. Saga lebih praktis.
💡 Kapan Choreography vs Orchestration
- Choreography = setiap service publish event, react terhadap event lain. Loose coupling tapi flow tidak eksplisit — sulit di-trace di saga panjang
- Orchestration = central orchestrator panggil step urut + handle compensation. Flow eksplisit, easier debug, tapi orchestrator jadi tight coupling point
Default: orchestration untuk saga > 3 step, choreography untuk simple chain.
⚠️ Jebakan klasik
- Compensation tidak idempotent = retry refund 2x = double refund
- Lupa compensation untuk step terakhir yang gagal = inconsistent state permanent
- Saga state hilang saat orchestrator crash = wajib persist saga state ke DB (state machine)
- Compensation gagal juga = wajib dead-letter queue + manual reconciliation
- Order ambigu di choreography = race condition, gunakan correlation ID + event timestamp
🎯 Saga implementation checklist
- State machine persist ke DB — tahu langkah ke berapa kalau crash
- Correlation ID pasang di tiap event/call — wajib untuk tracing
- Compensating action idempotent + tested — paling sering bug di sini
- Timeout tiap step — gak boleh tunggu selamanya
- Dead-letter queue untuk compensation gagal — manual reconciliation
- Observability — saga timeline visible di dashboard
TL;DR: Saga = transaksi distributed = chain local transaction + compensation kalau ada step gagal. Orchestration (eksplisit, debugable) atau Choreography (decoupled, sulit trace). Wajib idempotent compensation + correlation ID + state machine. Real-world default untuk multi-service workflows.