GH GambleHub

Outbox patterni

Outbox, domen hyzmatynyň öz ammaryndaky bir lokal amalda işewürlik üýtgemelerini we degişli wakany ýazýan binagärlik nusgasydyr. Wakany daşarky tekerde/nobata çap etmek "outbox" tablisasyny okaýan we ýazgylary yzyna iberýän aýratyn howpsuz proses (publisher) arkaly asinxron ýerine ýetirilýär. Bu çemeleşme "ilki DB-de, soň tekerde" ýaryşy ýok edýär we şowsuzlyklara garamazdan ygtybarly eltmegi üpjün edýär.

1) Haçan ulanmaly

Laýyk:
  • Kontekstleriň arasyndaky wakalar bilen mikroservisler we modully monolitler.
  • "Ýagdaýyň hasaba alnandygyny we wakanyň ýitip bilmejekdigini" kepillendirmek talap edilýär.
  • Idempotentlik we gözegçilik edilýän gaýtadan eltip bermek zerurdyr.
Laýyk däl:
  • Birnäçe çeşmelerde gaty global amallar möhümdir (aç-açan şertnamalar bilen TSS/saga has gowudyr).
  • Saýlanan hakykat çeşmesi ýok (state wakanyň döreýän ýerinde saklanmaýar).

2) Maksatlary we häsiýetleri

Atomic write: domen ýazgysy + outbox - bir amalda.
At-least-once neşir: gaýtalamaga ýol berýäris, ýitgini aradan aýyrýarys.
Sarp edijileriň idempotentligi: abonentleriň tarapynda dubllardan goramak.
Netijeli exactly-once: outbox + idempotent consumer + dedup kombinasiýasy arkaly gazanylýar.
Takyk telemetriýa: işewürlik amallarynyň we wakalaryň baglanyşygy.

3) Maglumatlaryň shemasy (mysal)

sql
-- Domain table (example: orders)
CREATE TABLE orders (
id       UUID PRIMARY KEY,
tenant_id    TEXT NOT NULL,
status     TEXT NOT NULL,
total_amount  NUMERIC(12,2) NOT NULL,
updated_at   TIMESTAMP NOT NULL DEFAULT now()
);

-- Outbox
CREATE TABLE outbox (
id       UUID PRIMARY KEY,        -- event_id aggregate_type TEXT NOT NULL,          -- 'order'
aggregate_id  UUID NOT NULL,          -- order_id tenant_id    TEXT NOT NULL,
type      TEXT NOT NULL,          -- 'OrderCreated'
payload JSONB NOT NULL, -- serialized headers event JSONB NOT NULL DEFAULT '{}':: jsonb,
occurred_at TIMESTAMP NOT NULL, -- time in domain transaction available_at TIMESTAMP NOT NULL, -- earliest publish time (backoff)
published_at TIMESTAMP, - is filled by the attempts INT NOT NULL DEFAULT 0,
error      TEXT
);

CREATE INDEX ON outbox (available_at) WHERE published_at IS NULL;
CREATE INDEX ON outbox (tenant_id, available_at) WHERE published_at IS NULL;

4) Amal şablony (application layer)

pseudo begin tx domainChange () # INSERT/UPDATE in domain table insert into outbox (event) # event with aggregate/tenant commit tx keys

Eger kommit üstünlikli bolsa, outbox-daky wakanyň bardygyna kepillik berilýär. Eger programma kommitden soň ýykylsa, mahabatlandyryjy ýeter.

5) Publisher (reader → publisher)

Maksatlar:
  • Çap edilmedik wakalary wagtal-wagtal okamak ('published _ at IS NULL' we 'available _ at <= now ()').
  • Teker/nobata ýerleşdirmäge synanyşyň; Üstünlikli bolsa, 'published _ at' belläň.
  • Hata edilse, 'attempts' -i köpeltmek, 'available _ at' -y geljege goýmak (exponential backoff), 'error' -y ýazmak.
  • Tenantlar/açarlar boýunça çäklere hormat goýmak (fairness), öndürijiligi blokirlemezlik.
Pseudo:
pseudo loop:
events = select from outbox where published_at is null and available_at <= now()
order by occurred_at limit BATCH_SIZE for update skip locked

for e in events:
try:
broker. publish(topicFor(e), serialize(e. payload), headers(e))
markPublished(e. id, now())
except Retryable:
backoff = computeBackoff(e. attempts)
reschedule(e. id, now()+backoff, attempts+1, last_error)
except NonRetryable:
moveToDLQ (e) or markError (e) # by sleep (POLL_INTERVAL) policy
💡 'FOR UPDATE SKIP LOCKED' köpçüligiň bäsdeşligini aradan aýyrýar.

6) Idempotentlik we duplikasiýa

Sarp edijiniň tarapynda (Inbox/Idempotency store):
sql
CREATE TABLE inbox (
consumer_name  TEXT,
event_id    UUID,
processed_at  TIMESTAMP NOT NULL,
PRIMARY KEY (consumer_name, event_id)
);

Algoritm: wakany alanyňyzda - ilki 'INSERT' -de 'inbox' synanyşygy; açar gapma-garşylygy ýüze çyksa - waka eýýäm işlenipdir → "no-op". Ondan soň - işewürlik logikasy.

Köpçüligiň gapdalynda: 'Idempotency-Key' -de (mysal üçin 'event _ id'), şina/broker/proksi dublikatlary süzüp biler ýaly.

7) Tertibi we sebäpliligi

'aggregate _ id' boýunça ýerli tertip 'occurred _ at' sortlamak we 'açar boýunça' çap etmek arkaly üpjün edilýär.
Partiýa ýerleşdirilen log-şinler üçin bir agregatyň wakalary bir partişende bolar ýaly 'aggregate _ id '/' tenant _ id' açary bilen partiýa goýuň.
Eger tertip möhüm bolsa, bir açardan köpçüligiň akymara ýaryşlaryndan gaça duruň.

8) CDC (Change Data Capture)

Işjeň köpçüligiň ýerine CDC ulanylyp bilner: hereketlendiriji DB amallar magazineurnalyny okaýar we 'outbox' setirlerini tekere ýaýradýar. Plýuslar - DB-e iň az ýük, takyk yzygiderlilik, pollingiň ýoklugy. Minuslar - operasiýany çylşyrymlaşdyrmak we DBB aýratynlyklaryna baglamak. Iki çemeleşme hem dogry; başarnyklar we SLO boýunça saýlaň.

9) Ýalňyşlyklar, DLQ we redrave

Retryable (tor, çäkler) - 'attempts' -i köpeldýäris, 'available _ at' -y yza süýşürýäris (exponential backoff + jitter).
Retryable däl (nolalid shema/kontrakt) - baý meta-maglumatlar bilen DLQ/Dead-Letter Topic-e geçirýäris.
Howpsuz redaktirleme: batçi, rate-limit, shema tassyklamasy, prod-traffigiň aşagyndaky ileri tutulýan ugur.

10) Köp tenantlyk we çäkler

Hökmany bellikler: 'tenant _ id', 'plan', 'region' - içinde 'outbox. headers`.
Per-tenant fairness: publişer neşirleriň "penjirelerini" we kärendeçiler boýunça synanyşyklaryň çäklerini paýlaýar.
Residency: outbox-y domen maglumatlary bolan sebitde saklaň; sebitara neşir etmek - diňe agregatlar/hasabatlar.

11) Howpsuzlyk we laýyklyk

PII-tenant/sebit syýasaty boýunça payload/headers-de redaksiýa.
Şina "keseki" bolsa, peýdaly ýüküň goly/şifrlemegi.
Ýagdaýyň ähli geçişleriniň barlagy: döredildi, çap edildi, ýalňyşlyk, redaktirlendi.

12) Gözegçilik etmek

Metrikler:
  • Çap möhleti ('now - occurred_at' p50/p95/p99).
  • Üstünlikleriň paýy, ýalňyşlyklaryň paýy, sebäpleriň paýlanyşy.
  • Outbox ululygy (çap edilmedik sany), synanyşyklar/sek.
  • Throughput we lag.
Söwda:
  • 'event _ id '/' aggregate _ id '/' saga _ id' baglanyşygy; "db-tx", "publish", "retry" ýataklary.
  • Düşündirişler: 'attempt', 'backoff _ ms', 'dlq = true'.
Logi:
  • Üstünlik üçin gysgaça ýazgylar; doly jikme-jiklikler/redrave.

13) Synag we bulam-bujarlyk

Atomicity synagy: çap edilmezden ozal domen amalynyň jemlenişinden soň emeli usulda "ýykylýar" - waka soň çykmaga borçludyr.
Duplicate test: Şol bir çäräni birnäçe gezek çap edýäris - konsumer takyk bir effekti (inbox) ýerine ýetirýär.
Order synagy: bir agregat boýunça wakalaryň bukjasy - yzygiderliligiň/idempotentligiň barlagy.
Chaos: dellalyň ret etmegi, DB-iň gizlinliginiň ýokarlanmagy, köpçüligiň bölünmegi, clock-skew.

14) Konfigurasiýa şablonlary (mysal)

yaml outbox:
poll_interval_ms: 200 batch_size: 200 order_by: occurred_at backoff:
strategy: exponential_full_jitter initial_ms: 250 max_ms: 10_000 max_attempts: 20 fairness:
per_tenant_parallelism: 4 per_key_serial: true

publisher:
rate_limit_per_sec: 500 headers:
idempotency_key: event_id schema_version: v3 dlq:
enabled: true topic: myapp. events. dlq include_metadata:
- error
- attempts
- source_table
- tenant_id
- aggregate_id

15) Saglar we retralar bilen integrasiýa

Outbox - saga ädimleri üçin "howpsuzlyk ulagy": ýerli geleşik effekti we buýrugy/wakany ýazýar; neşir - ygtybarly we dozaly.
Gaýtalama we backoff syýasatlary 'Retry-After' we Circuit Breaker bilen utgaşdyrylmalydyr; "retraý tupanyndan" gaça duruň.

16) Adaty ýalňyşlyklar

Domen ýagdaýy kommitinden soň bir waka ýazýarlar - ýykylanda ýitgiler bolup biler.
'outbox' -da indeksler/arhiw ýok → neşiriň gijikdirilmeginiň ýokarlanmagy.
Jemgyýetçilik 'SKIP LOCKED' -siz ýa-da şardlamasyz - bäsdeşlik we blokirleme.
Sarp edijilerde biperwaýlygyň ýoklugy - goşa we zyýanly täsirleri.
DLQ/loglarda gizlenmezden PII garyşdyrmak.
Fairness bolmasa neşiriň ýeke-täk global nobaty - "şowhunly" tenant hemmeleri haýalladýar.
Lagyň gözegçiliginiň ýoklugy → gizlin zaýalanmalar.

17) Strategiýany çalt saýlamak

Başlangyç derejesi: DB-den polling, 100-500 batçi, full-jitter backoff, konsumerlerde inbox.
Ýokary ýük: Geleşikler žurnalyndan CDC, kärendeçiler boýunça 'tenant _ id/aggregate _ id', WFQ boýunça şardlamak.
Agregat boýunça berk tertip: per key (mutex) seriýaly neşir etmek, topiki açar bilen partiýalaşdyrmak.
Complayens/PII: şifrlemek payload, redaksiýa DLQ, sebitleýin outbox.

18) Azyk önüminden öň çek-sanawy

  • Domen üýtgemeleri we 'outbox' ýazgysy bir amalda bolýar.
  • Publisher batchy gaýtadan işleýär, 'SKIP LOCKED', jitter bilen backoff we çäkleri ulanýar.
  • Konsumerler idempotentdir ('inbox '/dedup magazineurnaly).
  • DLQ we ygtybarly redaktirleme sazlandy.
  • Lagyň/ýalňyşlyklaryň metrikleri we p95/p99 çäkleri boýunça alertler.
  • Açaryň tertibi kepillendirilýär (partiýa/seriýa).
  • Arşiv/retenshn 'outbox' we çap edilen ýazgylary arassalamak.
  • PII-syýasatlar we ýagdaýlaryň geçişleriniň barlagy.
  • Kommit bilen neşiriň arasynda düşmek üçin synaglar, dublikatlar we tertip.
  • Wakanyň şertnamalarynyň resminamalary (shemalar/wersiýalar/laýyklyk).

Netije

"Outbox-pattern" "DB" şinanyň "" gowşak "toparyny ygtybarly konweýer konweýerine öwürýär: ýagdaýyň atom taýdan kesgitlenmegi, kepillendirilen (iň bolmanda" bir gezek "bolsa-da) neşir, idempotent abonentler we gözegçilik edilýän redaksiýa. Dogry telemetriýa, çäkler we shemalaryň düzgüni bilen, paýlanan amallaryň çylşyrymlylygyny peseldip, ulgamyň şowsuzlyklara we iň ýokary ýüklere garşylygyny ýokarlandyryp, amaly exactly-once özüni alyp barşyny berýär.

Contact

Biziň bilen habarlaşyň

Islendik sorag ýa-da goldaw boýunça bize ýazyp bilersiňiz.Biz hemişe kömek etmäge taýýar.

Telegram
@Gamble_GC
Integrasiýany başlamak

Email — hökmany. Telegram ýa-da WhatsApp — islege görä.

Adyňyz obýýektiw däl / islege görä
Email obýýektiw däl / islege görä
Tema obýýektiw däl / islege görä
Habar obýýektiw däl / islege görä
Telegram obýýektiw däl / islege görä
@
Eger Telegram görkezen bolsaňyz — Email-den daşary şol ýerden hem jogap bereris.
WhatsApp obýýektiw däl / islege görä
Format: ýurduň kody we belgi (meselem, +993XXXXXXXX).

Düwmäni basmak bilen siz maglumatlaryňyzyň işlenmegine razylyk berýärsiňiz.