Buyurtmalarni saga orqali qayta ishlash: to‘lov, ombor va yetkazish
Chuqur3 daqInnovialabs tahririyati
Qisqacha
Saga buyurtmani kompensatsiya amallari bo‘lgan lokal qadamlar ketma-ketligiga bo‘ladi, outbox va holat mashinasi esa hech bir hodisa yo‘qolmasligini va buyurtma ziddiyatli holatda qotib qolmasligini kafolatlaydi.
Sagalar moslik muammosini qanday hal qiladi
To‘lov, ombor va yetkazish alohida servislar yoki tashqi tizimlar bo‘lsa, barchasini qamrab oladigan bitta tranzaksiya yo‘q. Saga — lokal tranzaksiyalar zanjiri bo‘lib, har bir qadamning kompensatsiya amali bor: 3-qadam muvaffaqiyatsiz bo‘lsa, 2- va 1-qadamlar teskari tartibda bekor qilinadi.
Odatiy buyurtma sagasi:
| Qadam | Amal | Kompensatsiya |
|---|---|---|
| 1 | Buyurtmani pending statusida yaratish | Buyurtmani bekor qilish |
| 2 | Tovarni zaxiralash | Zaxirani olib tashlash |
| 3 | To‘lovni o‘tkazish | Pulni qaytarish |
| 4 | Jo‘natmani yaratish | Jo‘natmani bekor qilish |
| 5 | Buyurtmani tasdiqlash | — |
Natija — bir zumdagi emas, yakuniy moslik (eventual consistency): tizim qisqa vaqt oraliq holatda bo‘lishi mumkin, lekin doim to‘g‘ri yakunga keladi.
Taqsimlangan buyurtma nega buziladi
- Qisman muvaffaqiyat. Pul yechildi, ammo ombor taymauti sababli zaxira yaratilmadi.
- Ikki yozuv. Servis buyurtmani bazaga yozdi, lekin hodisani yuborishdan oldin yiqildi — boshqalar buyurtma haqida bilmay qoldi.
- Takrorlar. Tarmoq so‘rovni takrorladi va to‘lov ikki marta o‘tdi.
- Noma’lum natija. Taymaut rad etish degani emas: to‘lov o‘tgan bo‘lishi mumkin.
- Hodisalar tartibi. Bekor qilish tasdiqdan oldin keldi.
Tashqi API, to‘lov provayderlari va yetkazish xizmatlari o‘rtasida ikki fazali commit (2PC) odatda mavjud emas, shu sababli sagalar kerak.
Orkestratsiya yoki xoreografiya
Orkestratsiya — markaziy koordinator (orchestrator) saga holatini saqlaydi va servislarni navbat bilan chaqiradi.
Xoreografiya — servislar bir-birining hodisalariga javob beradi: OrderCreated → ombor zaxiralaydi → StockReserved → to‘lov yechadi va hokazo.
| Mezon | Orkestratsiya | Xoreografiya |
|---|---|---|
| Jarayon mantiqi qayerda | Bir joyda | Servislar bo‘ylab tarqalgan |
| Kuzatuvchanlik | Osonroq: saga holati ko‘rinadi | Hodisalarni trassirovka qilish kerak |
| Bog‘liqlik | Servislar orkestratorga bog‘liq | Servislar hodisalarga bog‘liq |
| Mos keladi | Tarmoqlanuvchi uzun jarayonlarga | 2-3 qadamli qisqa zanjirlarga |
To‘lov, ombor va yetkazishli buyurtma uchun orkestratsiyani qo‘llab-quvvatlash odatda tushunarliroq.
Buyurtma holat mashinasi
Buyurtmaning aniq statuslari va ruxsat etilgan o‘tishlari bo‘lishi kerak. Taqiqlangan o‘tish — jim yangilanish emas, xato.
pending -> stock_reserved -> paid -> shipping_created -> confirmed
pending | stock_reserved | paid -> compensating -> cancelled
Bu poygalardan himoya qiladi: allaqachon bekor qilingan buyurtma uchun PaymentSucceeded kelsa, tizim uni «tiriltirmaydi», balki pulni qaytarishni ishga tushiradi.
Transactional outbox
Nosozlikda hodisalarni yo‘qotmaslik uchun holat o‘zgarishi va hodisa bitta lokal tranzaksiyada yoziladi: buyurtmalar jadvaliga va outbox jadvaliga. Alohida jarayon outbox’ni o‘qib, xabarlarni brokerga chiqaradi.
BEGIN;
UPDATE orders SET status = 'stock_reserved' WHERE id = $1;
INSERT INTO outbox (aggregate_id, type, payload)
VALUES ($1, 'StockReserved', $2);
COMMIT;
Outbox at-least-once yetkazishni beradi, shuning uchun har bir iste’molchi idempotent bo‘lishi kerak: qayta ishlangan xabar id’larini saqlash yoki to‘lov API’siga idempotency key berish.
Nosozlik ssenariylari
- To‘lov rad etildi. Kompensatsiya: zaxirani olib tashlash, buyurtmani
cancelledga o‘tkazish, mijozni xabardor qilish. - To‘lov taymauti. Darhol bekor qilmang — provayderdan statusni so‘rang yoki webhook’ni kuting, keyin qaror qiling.
- Yetkazish xizmati ishlamayapti. Backoff bilan qayta urining; limitdan keyin pulni avtomatik qaytarish emas, qo‘lda ishlov berish.
- Kompensatsiyaning o‘zi yiqildi. Muvaffaqiyatga qadar takrorlang va alertga chiqaring; kompensatsiyalar idempotent bo‘lishi shart.
- Xabar ikki marta keldi. Idempotent ishlovchi takrorni e’tiborsiz qoldiradi.
Ko‘p uchraydigan xatolar
- Tashqi API’larni ma’lumotlar bazasi tranzaksiyasi ichida chaqirish.
- Taymautni rad etish deb hisoblash.
- «Qotib qolgan» sagalar uchun qo‘lda aralashuvni ko‘zda tutmaslik.
- Saga qadamlarini umumiy correlation id bilan loglamaslik.