WEB / WEB-19.02
Queue, producer, consumer ve worker
Public note için background indexing job’u hazırlanır. Queue teslimi, DB sonucu ve acknowledgement farklı adımlarda oluşur.
1. Core · Mekanizma
Hareket olmadan bütün senaryoları oku
Commit, sonra ack
- Job hazırlandı
Producer, job-note-1 için jobId, kind=index-public-note ve noteId=tea verisini hazırlar. Queue ve worker bu örnekte yerel adapter’lardır; henüz publication, delivery veya business commit yok.
- Producer
- Job-note-1 hazır
- Yerel queue
- Pending=0 / inflight=0
- Worker
- Teslim yok
- Business DB
- Result=0 / marker=0
- Queue işi kabul etti
Job pending listesine alınır. Kabul sonucu business işlemin tamamlandığını veya gerçek broker confirm alındığını göstermez.
- Producer
- Job-note-1 hazır
- Yerel queue
- Pending=1 / inflight=0
- Worker
- Teslim yok
- Business DB
- Result=0 / marker=0
- Worker teslim aldı
Job pending’den inflight’a geçer ve worker’a verilir. Sahne yerel queue teslimini gösterir.
- Producer
- Job-note-1 hazır
- Yerel queue
- Pending=0 / inflight=1
- Worker
- Job-note-1 / delivery=1
- Business DB
- Result=0 / marker=0
- Job verisi kontrol edildi
Worker kind, noteId ve jobId alanlarını beklenen biçime göre kontrol eder. Mesaj içeriği kod olarak çalıştırılmaz.
- Producer
- Job-note-1 hazır
- Yerel queue
- Pending=0 / inflight=1
- Worker
- Job schema kabul edildi
- Business DB
- Result=0 / marker=0
- Sonuç ve marker commit edildi
Business result ile processed marker aynı DB transaction’da commit edilir. Queue’nun inflight state’i ayrı kalır; ack henüz uygulanmamıştır.
- Producer
- Job-note-1 hazır
- Yerel queue
- Pending=0 / inflight=1
- Worker
- Job schema kabul edildi
- Business DB
- Result=1 / marker=1
- Ack hazırlanıyor
Worker commit sonucundan sonra ack vermeyi seçer. Ack işlemi DB commit’ini kendiliğinden doğrulamaz.
- Producer
- Job-note-1 hazır
- Yerel queue
- Pending=0 / inflight=1
- Worker
- Sonuç committed / ack hazır
- Business DB
- Result=1 / marker=1
- Ack uygulandı
Queue ack’i uygular ve inflight kaydını kaldırır. Bu değişim business result oluşturmaz; DB sonucu ayrı okunmalıdır.
- Producer
- Job-note-1 hazır
- Yerel queue
- Pending=0 / inflight=0
- Worker
- Sonuç committed / ack hazır
- Business DB
- Result=1 / marker=1
- İş sonucu ve teslim ayrıldı
Kayıt business result ile queue lifecycle’ını ayrı gösterir. HTTP caller’ın sonucu aldığı bu sahneden çıkmaz.
- Producer
- Business result hazır
- Yerel queue
- Pending=0 / inflight=0
- Worker
- Sonuç committed / ack hazır
- Business DB
- Result=1 / marker=1
Commit/ack gap
- Job hazırlandı
Producer, bilinen public note job’unu mesaj verisi olarak hazırlar. Queue henüz bu işi kabul etmemiştir.
- Producer
- Job-note-1 hazır
- Yerel queue
- Pending=0 / inflight=0
- Worker
- Teslim yok
- Business DB
- Result=0 / marker=0
- Queue işi kabul etti
Job pending listesine alınır. Kabul sonucu business işlemin tamamlandığını veya gerçek broker confirm alındığını göstermez.
- Producer
- Job-note-1 hazır
- Yerel queue
- Pending=1 / inflight=0
- Worker
- Teslim yok
- Business DB
- Result=0 / marker=0
- Worker teslim aldı
Job pending’den inflight’a geçer ve worker’a verilir. Sahne yerel queue teslimini gösterir.
- Producer
- Job-note-1 hazır
- Yerel queue
- Pending=0 / inflight=1
- Worker
- Job-note-1 / delivery=1
- Business DB
- Result=0 / marker=0
- Sonuç ve marker commit edildi
Business result ile processed marker aynı DB transaction’da commit edilir. Queue’nun inflight state’i ayrı kalır; ack henüz uygulanmamıştır.
- Producer
- Job-note-1 hazır
- Yerel queue
- Pending=0 / inflight=1
- Worker
- Job-note-1 / delivery=1
- Business DB
- Result=1 / marker=1
- Worker durdu, job geri alındı
Örnekte worker ack vermeden durur. Job tekrar pending olur; daha önceki business commit geri alınmaz.
- Producer
- Job-note-1 hazır
- Yerel queue
- Pending=1 / inflight=0
- Worker
- Job-note-1 / delivery=1
- Business DB
- Result=1 / marker=1
- Aynı job yeniden teslim edildi
Job-note-1 ikinci delivery ile worker’a gelir. Business job ID aynıdır; teslim instance’ı farklıdır.
- Producer
- Job-note-1 hazır
- Yerel queue
- Pending=0 / inflight=1
- Worker
- Job-note-1 / delivery=2
- Business DB
- Result=1 / marker=1
- Committed marker bulundu
Marker lookup önceki sonucu bulur ve ikinci business effect atlanır. Result row sayısı 1 kalır; dış effect’ler bu kontrolün kapsamında değildir.
- Producer
- Job-note-1 hazır
- Yerel queue
- Pending=0 / inflight=1
- Worker
- Job-note-1 / delivery=2
- Business DB
- Marker bulundu / result=1 korundu
- İkinci teslim ack aldı
Worker korunmuş business sonuçtan sonra ack verir ve inflight temizlenir. Bu örnek bütün sistem için exactly-once garantisi sağlamaz.
- Producer
- Job-note-1 hazır
- Yerel queue
- Pending=0 / inflight=0
- Worker
- Job-note-1 / delivery=2
- Business DB
- Marker bulundu / result=1 korundu
Early ack stop
- Job hazırlandı
Producer, bilinen public note job’unu mesaj verisi olarak hazırlar. Queue henüz bu işi kabul etmemiştir.
- Producer
- Job-note-1 hazır
- Yerel queue
- Pending=0 / inflight=0
- Worker
- Teslim yok
- Business DB
- Result=0 / marker=0
- Queue işi kabul etti
Job pending listesine alınır. Kabul sonucu business işlemin tamamlandığını veya gerçek broker confirm alındığını göstermez.
- Producer
- Job-note-1 hazır
- Yerel queue
- Pending=1 / inflight=0
- Worker
- Teslim yok
- Business DB
- Result=0 / marker=0
- Worker teslim aldı
Job pending’den inflight’a geçer ve worker’a verilir. Sahne yerel queue teslimini gösterir.
- Producer
- Job-note-1 hazır
- Yerel queue
- Pending=0 / inflight=1
- Worker
- Job-note-1 / delivery=1
- Business DB
- Result=0 / marker=0
- Commit öncesinde ack
Worker business commit olmadan ack vermeyi seçer. Sonraki durma halinde queue ile iş sonucu arasındaki boşluk burada açılır.
- Producer
- Job-note-1 hazır
- Yerel queue
- Pending=0 / inflight=1
- Worker
- Ack hazır / business result yok
- Business DB
- Result=0 / marker=0
- Ack uygulandı
Queue ack’i uygular ve inflight kaydını kaldırır. Bu değişim business result oluşturmaz; DB sonucu ayrı okunmalıdır.
- Producer
- Job-note-1 hazır
- Yerel queue
- Pending=0 / inflight=0
- Worker
- Ack hazır / business result yok
- Business DB
- Result=0 / marker=0
- İşlem öncesinde worker durdu
Örnekte worker business operation’dan önce durur. Queue’nun boşalması işin tamamlandığını göstermez.
- Producer
- Job-note-1 hazır
- Yerel queue
- Pending=0 / inflight=0
- Worker
- Business commit öncesi durdu
- Business DB
- Result=0 / marker=0
- Business result yok
Bağımsız lookup result row=0 ve marker=0 görür. Önceden ack alan job artık pending değildir.
- Producer
- Job-note-1 hazır
- Yerel queue
- Pending=0 / inflight=0
- Worker
- Business commit öncesi durdu
- Business DB
- Result=0 / marker=0
Outbox relay gap
- Update ve event aynı transaction’da
Producer note update ile event intent’i aynı DB transaction içinde hazırlamayı seçer.
- Producer
- Producer transaction hazır
- Yerel queue
- Pending=0 / inflight=0
- Worker
- Teslim yok
- Business DB
- Note version=1 / outbox=0
- İki kayıt henüz pending
Note version=2 ve outbox row aynı transaction’da bekler. Relay, commit edilmemiş event’i yayınlamaz.
- Producer
- Producer transaction hazır
- Yerel queue
- Pending=0 / inflight=0
- Worker
- Teslim yok
- Business DB
- Note=2 pending / outbox=1 pending
- İki kayıt birlikte commit edildi
COMMIT, note ve outbox kaydını görünür yapar. Queue’ya publish henüz yapılmamıştır.
- Producer
- Producer transaction hazır
- Yerel queue
- Pending=0 / inflight=0
- Worker
- Teslim yok
- Business DB
- Note=2 committed / outbox=1 pending
- Relay committed event’i okudu
Relay pending outbox row’u bağımsız read ile bulur ve bilinen job mesajını hazırlar.
- Producer
- Relay job-note-1 seçti
- Yerel queue
- Pending=0 / inflight=0
- Worker
- Teslim yok
- Business DB
- Note=2 committed / outbox=1 pending
- Queue publish’i kabul etti
Queue job’u pending olarak kabul eder. Database’deki sent marker henüz değişmez.
- Producer
- Relay job-note-1 seçti
- Yerel queue
- Pending=1 / inflight=0
- Worker
- Teslim yok
- Business DB
- Note=2 committed / outbox=1 pending
- Publish ile marker arasında durma
Relay publish sonrasında, sent marker güncellenmeden durur. Queue kabulü bilir; database kaydı hâlâ pending görünür.
- Producer
- Sent marker öncesi durdu
- Yerel queue
- Pending=1 / inflight=0
- Worker
- Teslim yok
- Business DB
- Note=2 committed / outbox=1 pending
- Outbox hâlâ pending
Bağımsız read note version=2 ve sent=false olan bir outbox row görür. Bu kayıt hiç publish yapılmadığını kanıtlamaz.
- Producer
- Sent marker öncesi durdu
- Yerel queue
- Pending=1 / inflight=0
- Worker
- Teslim yok
- Business DB
- Note=2 / outbox=1 / sent=false
- Retry tekrar publish etti
Relay aynı job’u yeniden queue’ya verir. Aynı business effect’i tekrarlamamak için consumer’ın job identity ve idempotency kontrolü gerekir.
- Producer
- Sent marker öncesi durdu
- Yerel queue
- Pending=2 / aynı job ID
- Worker
- Teslim yok
- Business DB
- Note=2 / outbox=1 / sent=false
ROLLER · STATE · VERİ AKIŞI
Queue işi ne zaman, kim için saklar?
Producer bir iş tanımını message olarak hazırlar. Atlas’ta job-note-1, public tea notunun indexlenmesini ister. Queue bekleyen işi tutar; consumer delivery’yi alır; worker application logic’i çalıştırır. Bu roller aynı process içinde veya ayrı service’lerde bulunabilir. Buradaki worker bir background application bileşenidir; browser Web Worker veya Service Worker API’si değildir. Queue’ya iş koymak, business sonucun oluştuğu veya HTTP caller’ın sonucu aldığı anlamına gelmez.
Background job, uzun veya ertelenebilir işi request lifecycle’dan ayırabilir. Accepted/pending yanıtı kullanıcıya işin devredildiğini anlatır; scheduled iş daha sonra başarısız da olabilir. Concurrency, capacity ve prefetch, bir worker’ın kaç outstanding delivery tuttuğunu etkiler. Evrensel tuning değeri yoktur. Atlas örneği tek job’u finite pending/inflight list’leriyle izler; gerçek broker veya parallel worker ölçümü yapmaz.
Message jobId, kind ve noteId alanlarını taşır. Application’ın seçtiği jobId business idempotency kimliğidir. RabbitMQ delivery tag ise channel içinde bir delivery’yi tanımlar; job kimliğiyle aynı şey değildir. Aynı job tekrar teslim edildiğinde delivery kimliği değişebilir. Message’ın bilinen schema ve purpose’a uyması gerekir; payload’ın varlığı permission kararı değildir ve içeriği code olarak çalıştırılmaz.
Ack, commit ve duplicate hangi sınırı geçer?
Publisher confirm, producer’ın broker’a publication sonucuyla ilgilidir. Consumer acknowledgement ise consumer delivery için ayrı bir sınırdır. Hiçbiri kendiliğinden application’ın business transaction sonucunu denetlemez. Atlas’ın manual-ack politikası önce result ile processed-job marker’ını aynı SQLite transaction’ında commit eder, sonra queue adapter’a ack verir. Ack, queue’nun inflight state’ini kaldırır. Erken ack verilip worker result’u kaydetmeden durursa queue artık işin beklediğini bilmez.
Commit başarılı olmuşken ack henüz görülmeden consumer durabilir. RabbitMQ manual acknowledgement akışında channel/connection kapanması unacked delivery’leri yeniden queue’ya alabilir. Atlas bunun küçük bir yerel modelini gösterir: aynı job ikinci kez gelir, committed marker bulunduğu için ikinci business effect üretilmez ve yeni delivery ack edilir. İki delivery, iki business effect değildir. Result ve marker aynı transaction içindedir; email, file veya dış API effect’i bu SQL sınırına otomatik katılmaz.
Producer’ın database update’i ile queue publish’ı da farklı owner’lara write’tır. Outbox pattern business row ve pending event row’unu aynı database transaction’ında saklar; relay daha sonra event’i publish eder. Publish ile sent marker arasında durma olursa aynı event tekrar publish edilebilir. Outbox bu nedenle consumer idempotency ihtiyacını kaldırmaz. Örneğin yerel relay state’i ve SQLite commit/rollback’i izlenir; universal exactly-once sonucu çıkarılmaz.
2. Red · Güven ve etki
Hareket olmadan bütün senaryoları oku
Erken ack
- İş teslim alındı
Worker job-note-1 işini teslim almış, fakat business result henüz commit edilmemiş. Delivery bilgisi result satırının yerine geçmez.
- Delivery / relay
- Delivery alındı; ack bekliyor
- Business database
- Business commit bekliyor
- Sonuç beklentisi
- Final sonuç bekliyor
- Ack business commit’ten önce
Bu dalda queue önce ack’i uyguluyor. Kendi outstanding state’ini kaldırabiliyor; database’de result olup olmadığını bu kararın parçası olarak denetlemiyor.
- Delivery / relay
- queueOutstanding=0
- Business database
- Business commit bekliyor
- Sonuç beklentisi
- Queue boş; sonuç henüz bilinmiyor
- Worker commit öncesinde durdu
Örnekte worker, ack sonrasında ve business commit öncesinde duruyor. Database sonucu oluşmuyor; queue’nun önceki ack bilgisi geri alınmış sayılmaz.
- Delivery / relay
- queueOutstanding=0
- Business database
- resultRows=0
- Sonuç beklentisi
- Worker commit öncesinde durdu
- Sonucu bağımsız kayıttan oku
Result owner’da resultRows=0 görülüyor. Queue boşluğu ile bu alan birlikte okunduğunda “iş tamamlandı” yorumu desteklenmiyor.
- Delivery / relay
- queueOutstanding=0
- Business database
- resultRows=0
- Sonuç beklentisi
- completedBusiness=false
- Queue completion’ı success’e çevirme
Ack, bu delivery için queue lifecycle’ını bitirmiştir. Business sonucunun oluştuğu başka bir owner’dan doğrulanmalıdır; burada completedBusiness=false.
- Delivery / relay
- queueOutstanding=0
- Business database
- resultRows=0
- Sonuç beklentisi
- completedBusiness=false
- Düzeltmenin ölçütü sonucu da kapsar
Normal dalda result ve processed marker aynı transaction’da commit edilir, ardından ack gelir. Kabul ölçütü yalnız boş queue değil, aynı job için business commit ve doğru ack sırasıdır.
- Delivery / relay
- Erken ack kaydı var
- Business database
- resultRows=0
- Sonuç beklentisi
- Commit ve ack ayrı doğrulanır
Relay aralığı
- Not ve event birlikte commit
Producer, noteVersion=2 ile pendingRows=1 değerlerini aynı database transaction’ında kaydediyor. Bu event’in publish edildiğini henüz söylemiyor.
- Delivery / relay
- Publish sonucu bekliyor
- Business database
- noteVersion=2 / pendingRows=1
- Sonuç beklentisi
- Database’de intent commit edildi
- Relay publish yaptı
publishEventsBeforeSentMarker=1: relay bir publish gerçekleştirmiş. Database’de sent marker henüz güncellenmediği için iki owner aynı tamamlanma bilgisini taşımıyor.
- Delivery / relay
- publishEvents=1
- Business database
- sentMarked=false
- Sonuç beklentisi
- Publish var; marker yok
- Publish ile sent marker arasında duruş
Relay publish sonrasında sent kaydını yazamadan durabilir. sentMarked=false değeri, publish’ın hiç gerçekleşmediği anlamına gelmez.
- Delivery / relay
- publishEvents=1 / relay stopped
- Business database
- sentMarked=false
- Sonuç beklentisi
- Publication cannot be inferred from sent=false
- Retry hangi bilgiyi görüyor?
Retry database’de pending event’i görüyor. Daha önce publish edilmiş aynı job için yeni bir publish yapılması mümkün; outbox bu belirsizliği tek başına kaldırmıyor.
- Delivery / relay
- duplicatePublishPossible=true
- Business database
- sentMarked=false
- Sonuç beklentisi
- Aynı job identity korunmalı
- Publish sayısı iki oldu
publishEventsAfterRetry=2. İki publish event’i, iki business effect gerçekleştiğini göstermez; consumer’ın aynı job’u nasıl değerlendirdiği ayrıca gerekir.
- Delivery / relay
- publishEventsAfterRetry=2
- Business database
- sameDatabaseTransaction=true
- Sonuç beklentisi
- Publish count != business effect count
- Outbox ile idempotency farklı işleri çözer
Outbox, business update ile event intent’ini aynı commit’e bağlar. Consumer idempotency ise aynı operation’ın tekrar tesliminde ikinci effect’i önler. External effect’ler bu SQLite transaction’ına kendiliğinden katılmaz.
- Delivery / relay
- publishEventsAfterRetry=2
- Business database
- externalEffectsInSqlTransaction=false
- Sonuç beklentisi
- Consumer idempotency ayrıca gerekir
VARSAYIM · SINIR · KONTROL
Queue state business state değildir
Accepted, inflight, business committed ve queue acked ayrı durumlardır. Erken ack dalında queueOutstanding=0 olmasına rağmen resultRows=0 kalır. Boş queue, tamamlanmış business işi kanıtlamaz. “Done” mesajı veya sayaç hangi owner’ın hangi işleminin bittiğini açıklamıyorsa öğrenci gerçek completion sınırını kaybeder.
Commit-before-ack dalında resultRows=1 ile inflight delivery birlikte bulunabilir. Worker’ın bu arada durması yeniden teslim ihtimalini bırakır. Artifact aynı job için deliveries=2 ve businessEffects=1 ayrımını görünür tutar. Bu ilişkinin dayanağı selected job identity ve committed marker’dır; herhangi bir queue ürününün etiketi değildir.
Idempotency marker hangi işi kapsar?
Marker jobId üzerinden business database’de tutulur. Marker ve result farklı transaction’larda yazılsaydı aradaki failure yeni bir gap yaratabilirdi. Örnekte ikisi aynı transaction’da hazırlanır; rollback dalında independent read ikisinin de olmadığını gösterir. Marker seçilen job kimliğini kapsar. Başka operation purpose veya external effect için aynı korumanın geçerli olduğu ayrıca gösterilmelidir.
Pending outbox row henüz publish edilmemiş olabilir; relay’in sent kaydı geciktiyse publish yapılmış da olabilir. Bu yüzden sent=false, “hiç consumer almadı” kanıtı değildir. Bilgi publication owner’ında ve business owner’ında farklı anlarda güncellenir. İnceleme aynı event için publish, sent marker, delivery ve committed effect observation’larını ayrı takip eder.
3. Blue · Güvenli geliştirme ve savunma
Hareket olmadan bütün senaryoları oku
Yeniden teslim
- İş kimliğini sabitle
Delivery sayısını yerel queue adapter’ı, result ile processed marker’ı bağımsız SQLite SELECT üretir. Aynı jobId ile eşleştirilen bu alanlar broker telemetry’si veya yakalanmış paket değildir. job-note-1, application’ın seçtiği business job identity’si. Queue delivery identity’si ile aynı alan değildir; yeniden teslimde önce aynı job’un geldiği doğrulanır.
- Delivery gözlemi
- jobId=job-note-1
- Result ve marker
- Result henüz okunmadı
- Kanıt yorumu
- Correlation pending
- Commit edilen marker’ı oku
Normal işleme result ve processed marker birlikte commit edilmiştir. Marker, bu job için mevcut business sonucu tarif eder; yalnız worker’ın “başladım” mesajı değildir.
- Delivery gözlemi
- jobId=job-note-1
- Result ve marker
- resultRows=1 / processedRows=1
- Kanıt yorumu
- Bu job için commit edilmiş sonuç
- Delivery sayısı iki
redelivery.deliveries=2 ve sameJobId=true. İki teslim, iki farklı business operation olduğunu göstermiyor.
- Delivery gözlemi
- deliveries=2 / sameJobId=true
- Result ve marker
- resultRows=1 / processedRows=1
- Kanıt yorumu
- Aynı operation yeniden geldi
- İkinci effect oluşmadı
businessEffects=1, processedMarkers=1 ve duplicateResultInserted=false birlikte okunur. Consumer ikinci teslimde mevcut marker’ı kullanmış; result yeniden eklenmemiş.
- Delivery gözlemi
- deliveries=2 / sameJobId=true
- Result ve marker
- businessEffects=1 / duplicateResultInserted=false
- Kanıt yorumu
- Aynı job’un ikinci effect’i önlendi
- Ack sonucu ayrıca görüldü
inflightAfterAck=0, queue tarafındaki son state’tir. Database’de tek result bulunması ile aynı alan değildir; her iki owner ayrı doğrulanır.
- Delivery gözlemi
- inflightAfterAck=0
- Result ve marker
- businessEffects=1 / processedMarkers=1
- Kanıt yorumu
- Queue ve database sonuçları ayrı
- Doğrulanan kapsamı koru
Bu yerel örnekte aynı job’un iki teslimi tek business effect bırakıyor. Bütün broker’lar, parallel worker’lar veya dış API effect’leri için universal exactly-once sonucu çıkarılmaz.
- Delivery gözlemi
- deliveries=2
- Result ve marker
- businessEffects=1 / processedMarkers=1
- Kanıt yorumu
- universalExactlyOnce=false
Rollback intent
- Commit ve rollback örneklerini ayır
Delivery sayısını yerel queue adapter’ı, result ile processed marker’ı bağımsız SQLite SELECT üretir. Aynı jobId ile eşleştirilen bu alanlar broker telemetry’si veya yakalanmış paket değildir. Outbox kaydı iki transaction sonucu içeriyor. Başlık değişikliği ile event intent’inin aynı transaction içinde olup olmadığını bu iki dalı karşılaştırarak incelersin.
- Delivery gözlemi
- Publish henüz incelenmedi
- Result ve marker
- Commit / rollback dalları
- Kanıt yorumu
- Atomic intent henüz doğrulanmadı
- Commit dalında iki sonuç birlikte
Commit dalında noteVersion=2 ve pendingRows=1. Yeni not revision’ı ile publish intent’i aynı database sınırında kalıyor.
- Delivery gözlemi
- Publish henüz incelenmedi
- Result ve marker
- commit: noteVersion=2 / pendingRows=1
- Kanıt yorumu
- sameDatabaseTransaction=true
- Rollback dalında event çıkmıyor
Rollback dalında noteVersion=1 ve pendingRows=0. Başarısız transaction, yeni revision veya committed pending event bırakmıyor.
- Delivery gözlemi
- Publish henüz incelenmedi
- Result ve marker
- rollback: noteVersion=1 / pendingRows=0
- Kanıt yorumu
- Database’de intent rollback gözlendi
- Bu kanıt hangi soruyu cevaplıyor?
Karşılaştırma business row ile event intent’inin birlikte commit/rollback olduğunu destekler. Queue consumer’ın tamamlandığını veya caller’ın sonucu gördüğünü göstermez.
- Delivery gözlemi
- Consumer sonucu bilinmiyor
- Result ve marker
- sameDatabaseTransaction=true
- Kanıt yorumu
- Intent atomicity != end-to-end completion
- Relay başka bir owner sınırı
Relay daha sonra pending event’i publish eder. Publish sonucu ile sent marker arasında bir aralık bulunabileceği için önceki transaction’ın atomikliği bütün zinciri atomik yapmaz.
- Delivery gözlemi
- duplicatePublishPossible=true
- Result ve marker
- sameDatabaseTransaction=true
- Kanıt yorumu
- Consumer sonucu bilinmiyor
- Kabul ölçütünü katmanlara böl
Database intent’i, publish gözlemi, aynı job için consumer result ve ack ayrı ölçütlerdir. Bir ölçütün başarılı olması, diğer alanlar eksikken bütün işi başarılı saydırmaz.
- Delivery gözlemi
- Publish kanıtı gerekir
- Result ve marker
- Intent’in atomikliği gözlendi
- Kanıt yorumu
- Result ve ack için ayrı kanıt gerekir
UYGULAMA · GÜVENLİK KONTROLÜ · DOĞRULAMA
Completion ve retry policy açık olsun
Delivery sayısını yerel queue adapter’ı, result ile processed marker’ı bağımsız SQLite SELECT üretir. Aynı jobId ile eşleştirilen bu alanlar broker telemetry’si veya yakalanmış paket değildir. Worker, kind=index-public-note ve noteId=tea için bilinen message schema’sını değerlendirir. Delivery alınca inflight state oluşur; business commit sonrası manual ack bunu kaldırır. Independent SELECT ile result ve processed marker’ın aynı job’a ait olduğu incelenir. Queue state’ini database sonucu yerine kullanma; code execution ile message parsing’i de karıştırma.
Commit sonrası, ack öncesi durma dalında ikinci delivery aynı jobId’yi taşır. Worker committed marker’ı bulduğunda yeni result yazmaz. Ack intent’i ile broker’ın ack’i alması gerçek network’te ayrı gözlemlerdir. Atlas’ın yerel adapter’ı method return’de kendi state’ini değiştirir; bunu yakalanmış network packet gibi çizmez. Gerçek broker için channel ve recovery davranışı ayrı doğrulanır.
Outbox ve bounded work farklı kontrollerdir
Producer note update’i ile outbox event’ini aynı transaction’da commit eder; rollback olmuş iş yeni event bırakmaz. Relay yalnız committed pending row’ları publish eder. Publish sonrası sent marker gecikmesi duplicate bırakabileceğinden consumer aynı job’un effect’ini ayrıca sınırlar. External effect’i bu transaction’a dahil etmek gerekiyorsa onun owner’ı ve failure sınırı da tasarıma eklenir.
Worker capacity, retry sayısı ve failed-job handling product policy’sidir. Sonsuz retry’nin yerine kaç deneme yapılacağı, hangi hata için yeniden deneneceği ve hangi final durumun kullanıcıya bildirileceği açık olmalıdır. Ack transaction’ın yerine geçmez; queue durability de business result durability’sini kanıtlamaz. Aynı job için kabul, delivery, commit ve notification ayrı sonuçlar olarak kalır.
ŞİMDİ VAKAYA UYGULA
Publish, delivery, business commit ve ack hangi owner’ın tamamlanmasıdır?
Atlas, public tea notunu indexlemek için job-note-1 işini hazırlıyor. Queue bu işi artık outstanding saymayabilir; buna rağmen bağımsız result kaydında hiçbir satır bulunmayabilir. İşin teslim edilmesi ile işin sonucu ayrı izlenir.
Vakadaki accepted, delivery ve committed effect kayıtlarını farklı owner’lar üzerinden oku. Caller’ın bilinmeyen sonucunu business rollback olarak yeniden adlandırma.
Bağlı vaka dosyasını aç ↗ÖRNEĞİ BİRLİKTE OKUYALIM
Public note job/delivery/outbox ledger
Bir alan seç; hangi sonucu desteklediğini ve nerede yetersiz kaldığını incele.
Ham kaydı ve alan açıklamalarını oku
{
"job": {
"jobId": "job-note-1",
"kind": "index-public-note",
"noteId": "tea",
"dataIsCode": false
},
"normal": {
"pendingAfterPublish": 1,
"inflightAfterDelivery": 1,
"resultRowsAfterCommit": 1,
"processedRowsAfterCommit": 1,
"pendingAfterAck": 0,
"inflightAfterAck": 0,
"publisherConfirmIsBusinessResult": false
},
"redelivery": {
"deliveries": 2,
"businessEffects": 1,
"processedMarkers": 1,
"sameJobId": true,
"duplicateResultInserted": false,
"inflightAfterAck": 0
},
"earlyAck": {
"queueOutstanding": 0,
"resultRows": 0,
"completedBusiness": false,
"failure": "injected stop after ack before business commit"
},
"outbox": {
"commit": {
"noteVersion": 2,
"pendingRows": 1
},
"rollback": {
"noteVersion": 1,
"pendingRows": 0
},
"relay": {
"publishEventsBeforeSentMarker": 1,
"sentMarked": false,
"duplicatePublishPossible": true,
"publishEventsAfterRetry": 2
},
"sameDatabaseTransaction": true
},
"limits": {
"brokerExecuted": false,
"simulation": "own finite Python queue adapter + sqlite3 business/outbox state",
"externalEffectsInSqlTransaction": false,
"universalExactlyOnce": false
},
"selector": {
"language": "XPath",
"xml": "<audit><job queueAcked=\"true\" businessCommitted=\"true\"/></audit>",
"xpath": "count(/audit/job[@queueAcked='true' and @businessCommitted='false'])",
"expected": 0,
"positiveFixtureXml": "<audit><job queueAcked=\"true\" businessCommitted=\"false\"/></audit>",
"positiveExpected": 1,
"scope": "Only authored protocol-decision observations, not product log field names or a live HTTP capture.",
"missingFieldBehavior": "Missing observation is insufficient evidence; zero matches is not proof of correct runtime behavior."
}
}- job
- Known public-note job schema; inert data.
- normal/redelivery/earlyAck
- Business result ile delivery/ack ayrı outcomes.
- outbox
- Same database intent commit ve finite relay gap.
- selector
- Synthetic early acknowledgement boundary.
Own queue simulation ve local SQLite only; real RabbitMQ/Kafka/SQS, parallel workers veya universal exactly-once testi değildir.
İki yanlış kanı
Queue ack veya publisher confirm business transaction’ın commit’ini kanıtlar.
Bunlar ayrı delivery/publication scopes’tur; business result owner’ı ayrıca doğrulanır.
Outbox varsa duplicate job veya idempotency düşünmeye gerek yoktur.
Relay publish/sent gap’i duplicates bırakabilir; selected consumer business effect’i kendi transaction boundary’sinde idempotent tutar.
SIRA SENDE
Bu hikâyeyi sen çöz.
Sonucu tahmin et, kanıtın sınırını bul ve nedenini kendi cümlenle anlat.
Queue için erken ACK verildi, fakat resultRows=0. Job’ın business işlemi tamamlanmış mıdır?
- Evet. Queue ACK bütün business effect’lerini commit eder.
- Hayır. outstanding=0 olsa da completedBusiness=false.
Gerekçeli cevabı oku
Hayır. outstanding=0 olsa da completedBusiness=false. — ACK, broker’daki bekleyen delivery’yi bitirir. Bu örnekte business commit yapılmadan durulduğu için sonuç üretilmemiştir.
Delivery sayısı 2 iken businessEffects=1 olması nasıl mümkün?
Dersten seçilen artifact alanları; öğretim örneği
- redelivery
- {"deliveries":2,"businessEffects":1,"processedMarkers":1,"sameJobId":true,"duplicateResultInserted":false,"inflightAfterAck":0}
- Duplicate kontrolü aynı job’ın effect’ini ikinci kez uygulamaz.
- İki delivery mutlaka iki business effect oluşturur.
Gerekçeli cevabı oku
Duplicate kontrolü aynı job’ın effect’ini ikinci kez uygulamaz. — sameJobId=true ve processedMarkers=1, bu örneğin business idempotency kapsamını gösterir. Bu sonuç transport için exactly-once garantisi değildir.
Outbox relay publish etti, fakat sent marker yazılmadı. Retry neden duplicate publish oluşturabilir? Outbox hangi işlemleri atomic tutar?
Gerekçeli cevabı oku
Database transaction’ı note version ile pending outbox row’unu birlikte commit veya rollback eder. Relay’in publish etmesi ve sent marker yazması bu yerel transaction’ın dışındadır. Publish sonrasında marker yazılamazsa retry aynı kaydı yeniden publish edebilir. Consumer idempotency ayrıca gerekir. Örnek external effect’leri SQL transaction’ına dahil etmez ve gerçek broker çalıştırmaz.
□ Outbox’ın yerel atomicity kapsamını end-to-end exactly-once’dan ayırdım.
□ Publish ile sent marker arasındaki boşluğun duplicate doğurabileceğini açıkladım.
Uygulama konsolunu aç · request / response / browser
Request, URL, cookie ve DOM örneklerini ayrıca aç
Kaynaklar ve kapsam
- RabbitMQ — Work Queues tutorialWhat This Tutorial Focuses On · Message acknowledgment · Fair dispatch
- RabbitMQ 4.3 — Consumer acknowledgements and publisher confirmsAre Publisher Confirms Related to Consumer Delivery Acknowledgements? · Consumer Acknowledgement Modes and Data Safety Considerations · When Consumers Fail or Lose Connection: Automatic Requeueing
- RabbitMQ 4.3 — ConsumersTerminology · Consumer Lifecycle · Acknowledgement Modes · Limiting Simultaneous Deliveries with Prefetch
- AWS Prescriptive Guidance — Transactional outboxIntent · Motivation · Issues and considerations · Using an outbox table
- SQLite — Transaction2. Transactions · 2.1. Read transactions versus write transactions · 2.2. DEFERRED, IMMEDIATE, and EXCLUSIVE transactions · 2.3. Implicit versus explicit transactions
- Python 3.14 — sqlite3Tutorial · sqlite3.connect · Cursor.execute · How to use placeholders to bind values in SQL queries · Transaction control via the isolation_level attribute · How to use the connection context manager