Bosh sahifa Wiki Transactional Outbox

Transactional Outbox

Transactional Outboxdatabase’dagi business o‘zgarish va tashqi brokerga yuborilishi kerak bo‘lgan event haqidagi yozuvni bitta local transactionda saqlaydigan integration pattern. Keyin alohida publisher outbox table’dan eventlarni olib message brokerga yuboradi.

Pattern database commit va message publish orasidagi dual-write nomuvofiqligini kamaytiradi.

Dual-write muammosi

Application quyidagilarni bajaradi:

  1. orderni database’ga saqlaydi;
  2. OrderCreated eventini brokerga yuboradi.

Database commit muvaffaqiyatli, publish xato bo‘lsa order bor, ammo event yo‘q.

Publish oldin, database commit xato bo‘lsa event mavjud bo‘lmagan order haqida xabar beradi.

Outbox table

Business table bilan bir database’da outbox table yaratiladi.

Fieldlar:

Order va outbox row bitta transactionda yoziladi.

Local transaction

BEGIN
→ orders INSERT
→ outbox INSERT
→ COMMIT

Commit bo‘lsa ikkalasi ham mavjud.

Rollback bo‘lsa ikkalasi ham yo‘q.

Distributed transaction yoki brokerning database transactionida qatnashishi talab qilinmaydi.

Publisher

Background worker outbox rowlarni o‘qiydi va brokerga yuboradi.

Muvaffaqiyatli publishdan keyin row:

  • published deb belgilanadi;
  • o‘chiriladi;
  • archive qilinadi.

Publisher bir nechta instance bilan parallel ishlashi mumkin.

Polling publisher

Worker davriy query qiladi:

status = pending

Rowlarni batch bilan lock qilib oladi.

SKIP LOCKEDga o‘xshash mexanizm parallel workerlar bir rowni olishini kamaytiradi.

Polling interval latency va database load o‘rtasida muvozanat qiladi.

Log-based publisher

Change Data Capture transaction logdagi outbox insertlarni kuzatib brokerga uzatadi.

Bu polling querylarini kamaytiradi va past latency beradi.

Evaziga CDC infrastructure, offset va schema boshqaruvi kerak.

At-least-once delivery

Publisher eventni brokerga yubordi, ammo outbox statusini update qilishdan oldin crash qilishi mumkin.

Restartda event yana yuboriladi.

Shu sababli pattern odatda at-least-once delivery beradi.

Consumer duplicate eventga tayyor bo‘ladi.

Event ID

Har outbox event unique IDga ega.

Consumer processed event IDlarni saqlab deduplication qilishi mumkin.

Event ID retryda o‘zgarmaydi.

Yangi ID yaratish duplicate’ni aniqlashni imkonsiz qiladi.

Idempotent consumer

Handler bir eventni bir necha marta olganda yakuniy holat buzilmaydi.

Masalan:

invoice statusini CREATED qilish

idempotent bo‘lishi mumkin.

balance += amount

esa event ID yoki ledger unique constraint talab qiladi.

Ordering

Bir aggregate eventlari tartibi muhim bo‘lishi mumkin.

Outbox:

saqlaydi.

Broker partition key sifatida aggregate ID ishlatiladi.

Parallel publisherlar bir aggregate tartibini buzmasligi kerak.

Payload

Outbox payload event consumerlariga kerakli minimal data’ni saqlaydi.

Variantlar:

Faqat entity ID yuborilsa consumer keyin source service’ga query qilib, boshqa versionni olishi mumkin.

Schema version

Event format vaqt o‘tishi bilan o‘zgaradi.

Payload schema version saqlaydi.

Consumer eski va yangi versiyani bir muddat tushunishi kerak.

Breaking change yangi event type yoki migration talab qilishi mumkin.

Failure va retry

Publish xatosida:

  • attempt oshadi;
  • next retry time;
  • exponential backoff;
  • error summary

saqlanadi.

Doimiy invalid event dead-letter yoki manual review holatiga o‘tkaziladi.

Cheksiz tez retry database va brokerni band qiladi.

Cleanup

Published outbox rowlar table’ni cheksiz o‘stirmasligi kerak.

Policy:

  • ma’lum kundan keyin delete;
  • monthly partition drop;
  • archive;
  • audit retention.

Pending rowlar tasodifan cleanup qilinmaydi.

Backlog

Outbox publisher ishlamasa pending rowlar yig‘iladi.

Kuzatiladi:

  • pending count;
  • eng eski event yoshi;
  • publish rate;
  • failure;
  • attempt;
  • table size.

Database normal ishlayotgani eventlar yetkazilayotganini kafolatlamaydi.

Transaction boundary

Outbox row aynan business o‘zgarishi bilan bir transactionda yozilishi kerak.

Eventni transaction commitdan keyin application memory’da yaratish pattern kafolatini buzadi.

ORM hook va callback transaction semantikasiga mos ishlatiladi.

Inbox bilan birga

Consumer kelgan message’ni processed registry yoki inbox table’da saqlashi mumkin.

Business update va event ID recording bitta transactionda bajariladi.

Bu duplicate processingni boshqaradi.

Outbox va Inbox birgalikda ishonchli event workflow beradi.

Publisher locking

Bir nechta publisher pending rowlarni parallel olganda bir event ikki workerga bir vaqtda tushmasligi uchun row lock yoki claim field ishlatiladi.

Claim lease bilan cheklanadi.

Worker crash qilsa event keyin qayta olinadi.

Partitioning

Katta outbox table vaqt bo‘yicha partition qilinadi.

Published eski partitionlar tez drop yoki archive qilinadi.

Pending event boshqa partitionda qolib ketmasligi uchun cleanup statusni tekshiradi.

Event visibility

Business transaction commit bo‘lmagunga qadar outbox row publisherga ko‘rinmasligi kerak.

Isolation va polling query aynan committed eventlarni oladi.

Replica’dan polling qilinsa replication lag event deliveryni kechiktirishi mumkin.

Payload maxfiyligi

Outbox table database backup va administratorlarga ko‘rinadi.

Shu sababli token, parol va keraksiz personal data event payloadga yozilmaydi.

Zarur maxfiy field encryption va qisqa retention bilan boshqariladi.

Bog‘liq tushunchalar

Dual write, Domain event, Message broker, Change Data Capture, At-least-once delivery, Idempotent consumer, Outbox table, Inbox pattern, Event-driven architecture