WEB / WEB-19.S01
Races, transactions ve idempotency
Note okunduktan sonra revision değişebilir. Eski koşul, DB commit ve caller’ın sonucu öğrenmesi arasındaki farkı izle.
1. Core · Mekanizma
Hareket olmadan bütün senaryoları oku
Commit sonucu
- Operation hazırlandı
Caller, public note işlemini purpose ve key alias ile hazırlar. Bu key bir credential değildir.
- Caller
- Public note işlemi
- Service
- Request scope seçildi
- Note DB
- Tea note / version=1 committed
- Saved result
- Saved result yok
- Scope eşleştirildi
Service caller, purpose ve key’i note/title parameters ile eşleştirir. Aynı key’in hangi işlem kapsamında kullanılacağı belirlenir.
- Caller
- Public note işlemi
- Service
- Scope+parameters eşleştirildi
- Note DB
- Tea note / version=1 committed
- Saved result
- Saved result yok
- Mutation henüz pending
Rename transaction içinde hazırlanır. Bağımsız observer hâlâ önceki committed note’u görür.
- Caller
- Public note işlemi
- Service
- Scope+parameters eşleştirildi
- Note DB
- Pending: Updated note / version=2
- Saved result
- Saved result yok
- Mutation ve result birlikte commit
Note değişikliği ile normalize edilmiş parameters ve saved result aynı SQL transaction’da commit edilir. Dış effect bu transaction’a dahil değildir.
- Caller
- Public note işlemi
- Service
- Scope+parameters eşleştirildi
- Note DB
- Updated note / version=2 committed
- Saved result
- Committed result: Updated note / version=2
- Caller sonucu öğrendi
Caller noteId, title ve version sonucunu yerel tamamlanma adımında öğrenir. Gerçek HTTP teslimi ayrıca gözlenmelidir.
- Caller
- Updated note / version=2 / mutationCount=1
- Service
- Scope+parameters eşleştirildi
- Note DB
- Updated note / version=2 committed
- Saved result
- Committed result: Updated note / version=2
Eski revision
- Operation hazırlandı
Caller, public note işlemini purpose ve key alias ile hazırlar. Bu key bir credential değildir.
- Caller
- Public note işlemi
- Service
- Request scope seçildi
- Note DB
- Tea note / version=1 committed
- Saved result
- Saved result yok
- Revision 1 okundu
Uygulama revision=1 okur. Verinin sonraki kullanıma kadar değişmeden kalacağı garanti değildir.
- Caller
- Okunan expected=1
- Service
- Request scope seçildi
- Note DB
- Tea note / version=1 committed
- Saved result
- Saved result yok
- Başka update commit edildi
Bağımsız note değişikliği store’da Coffee note ve version=2 oluşturur. Önceki read artık current değildir.
- Caller
- Okunan expected=1
- Service
- Request scope seçildi
- Note DB
- Coffee note / version=2
- Saved result
- Saved result yok
- Expected revision DB’ye taşındı
Service expected=1 koşulunu authoritative UPDATE’e bound value olarak verir. Yalnız eski UI kontrolüne güvenmez.
- Caller
- Okunan expected=1
- Service
- Expected=1 / current=2 koşulu
- Note DB
- Coffee note / version=2
- Saved result
- Saved result yok
- Eski revision reddedildi
Guarded statement rowcount=0 üretir. Current title ve revision korunur; eski operation mutation yapmamıştır.
- Caller
- Okunan expected=1
- Service
- Expected=1 / current=2 koşulu
- Note DB
- Coffee note / version=2 / changedRows=0
- Saved result
- Saved result yok
- Conflict sonucu
Caller conflict sonucunu öğrenir. Reddedilmiş eski operation business mutation olarak sayılmaz.
- Caller
- Conflict / current state korundu
- Service
- Expected=1 / current=2 koşulu
- Note DB
- Coffee note / version=2 / changedRows=0
- Saved result
- Saved result yok
Unknown + retry
- Operation hazırlandı
Caller, public note işlemini purpose ve key alias ile hazırlar. Bu key bir credential değildir.
- Caller
- Public note işlemi
- Service
- Request scope seçildi
- Note DB
- Tea note / version=1 committed
- Saved result
- Saved result yok
- Scope eşleştirildi
Service caller, purpose ve key’i note/title parameters ile eşleştirir. Aynı key’in hangi işlem kapsamında kullanılacağı belirlenir.
- Caller
- Public note işlemi
- Service
- Scope+parameters eşleştirildi
- Note DB
- Tea note / version=1 committed
- Saved result
- Saved result yok
- Mutation henüz pending
Rename transaction içinde hazırlanır. Bağımsız observer hâlâ önceki committed note’u görür.
- Caller
- Public note işlemi
- Service
- Scope+parameters eşleştirildi
- Note DB
- Pending: Updated note / version=2
- Saved result
- Saved result yok
- Mutation ve result birlikte commit
Note değişikliği ile normalize edilmiş parameters ve saved result aynı SQL transaction’da commit edilir. Dış effect bu transaction’a dahil değildir.
- Caller
- Public note işlemi
- Service
- Scope+parameters eşleştirildi
- Note DB
- Updated note / version=2 committed
- Saved result
- Committed result: Updated note / version=2
- Caller sonucu bilmiyor
Örnekte caller ilk tamamlanma bilgisini alamaz. Database commit’i korunur; eksik response rollback değildir.
- Caller
- İlk result bilgisi unknown
- Service
- Scope+parameters eşleştirildi
- Note DB
- Updated note / version=2 committed
- Saved result
- Committed result: Updated note / version=2
- Aynı scope ile retry
Aynı purpose, key ve parameters ile stored result aranır. Yeni işlem başlatmadan önce önceki tamamlanma kaydı değerlendirilir.
- Caller
- İlk result bilgisi unknown
- Service
- Aynı scope+parameters ile retry
- Note DB
- Updated note / version=2 committed
- Saved result
- Committed result: Updated note / version=2
- Saved result tekrar kullanıldı
Stored result bulunur ve ikinci note mutation yapılmaz. Result record sayısı 1 kalır.
- Caller
- İlk result bilgisi unknown
- Service
- Aynı scope+parameters ile retry
- Note DB
- Updated note / version=2 committed
- Saved result
- Saved result kullanıldı / mutationCount=1
- Caller sonucu öğrendi
Caller noteId, title ve version sonucunu yerel tamamlanma adımında öğrenir. Gerçek HTTP teslimi ayrıca gözlenmelidir.
- Caller
- Updated note / version=2 / mutationCount=1
- Service
- Aynı scope+parameters ile retry
- Note DB
- Updated note / version=2 committed
- Saved result
- Saved result kullanıldı / mutationCount=1
Rollback result
- Operation hazırlandı
Caller, public note işlemini purpose ve key alias ile hazırlar. Bu key bir credential değildir.
- Caller
- Public note işlemi
- Service
- Request scope seçildi
- Note DB
- Tea note / version=1 committed
- Saved result
- Saved result yok
- Scope eşleştirildi
Service caller, purpose ve key’i note/title parameters ile eşleştirir. Aynı key’in hangi işlem kapsamında kullanılacağı belirlenir.
- Caller
- Public note işlemi
- Service
- Scope+parameters eşleştirildi
- Note DB
- Tea note / version=1 committed
- Saved result
- Saved result yok
- Mutation henüz pending
Rename transaction içinde hazırlanır. Bağımsız observer hâlâ önceki committed note’u görür.
- Caller
- Public note işlemi
- Service
- Scope+parameters eşleştirildi
- Note DB
- Pending: Updated note / version=2
- Saved result
- Saved result yok
- Result kaydı oluşturulamadı
NOT NULL koşulu saved result kaydını reddeder. Mutation bu anda hâlâ pending durumdadır; sonraki adımda explicit rollback hem mutation’ı hem result kaydını geri alır.
- Caller
- Public note işlemi
- Service
- Scope+parameters eşleştirildi
- Note DB
- Pending: Updated note / version=2
- Saved result
- Constraint hatası / kayıt yok
- Transaction geri alındı
Database Tea note ve version=1 kaydını korur. Operation result record’u commit edilmemiştir.
- Caller
- Public note işlemi
- Service
- Scope+parameters eşleştirildi
- Note DB
- Tea note / version=1 korundu
- Saved result
- Result record=0
- Caller başarısızlığı biliyor
Caller failure sonucunu öğrenir. Bu, commit başarılıyken response’un bilinmediği durumla aynı sonuç değildir.
- Caller
- Failure / rollback gözlendi
- Service
- Scope+parameters eşleştirildi
- Note DB
- Tea note / version=1 korundu
- Saved result
- Result record=0
ROLLER · STATE · VERİ AKIŞI
Bir read sonraki use için söz vermez
Application public notu revision=1 olarak okur. Operation uygulanana kadar authoritative owner’daki not revision=2’ye değişebilir. TOCTOU, check sırasında bilinen state ile use sırasındaki state arasındaki bu boşluğu anlatır. Order-dependent davranış, lost update ve invariant ihlali aynı sonuç değildir. Atlas örneği sıradan bir revision değişimi sonrasında guarded update’in eski expectation’ı reddetmesini gösterir.
Kontrol, UI’daki eski check’i tekrar etmek yerine operation condition’ını authoritative statement içinde değerlendirir. Örneğin UPDATE, note ID ve expected revision için bound values kullanır. Expected revision=1 iken current revision=2 olduğunda affectedRows=0 olur ve current title/revision korunur. Transaction açmak yanlış application predicate’ini doğru yapmaz. Korunacak invariant hangi row, field ve operation’ı kapsıyorsa açıkça tanımlanmalıdır.
Transaction visibility başka bir sorudur. Seçilen SQLite ayarlarında independent connection uncommitted update’i görmez; commit sonrasında okuyabilir. Bu, revision predicate’inin doğruluğundan ve HTTP caller’ın yanıt almasından ayrıdır. Örnekte before/after revision ve affected-row count sırayla gözlenir. Gerçek concurrent traffic veya timing ölçümü yerine finite state geçişleri incelenir.
Retry kimliğinin result ve purpose’u vardır
Caller completion response’unu alamadığında operation’ın hiç çalışmadığını bilemez. Atlas’ta note rename commit olur fakat caller’ın bilgisi UNKNOWN kalır. Aynı request alias ve aynı parameters ile retry committed result’u yeniden kullanır. Idempotency scope caller alias, operation purpose ve key’den oluşur; normalized note ID/title parameters da kaydedilir. Aynı scope/key farklı parameters ile gelirse conflict oluşur; önceki result başka intent adına sunulmaz.
Idempotency record ile business mutation aynı SQLite transaction’ında commit edilir. Zararsız NOT NULL failure dalında explicit rollback ikisini de bırakmaz. Record’un kendisi bir garanti değildir: server anlamını, validation’ını, retention’ını ve key reuse davranışını tanımlar. Stripe’ın saved status/body ve parameter comparison contract’ı buna bir örnektir; farklı product’larda failure retention veya pruning sonrası davranış farklı olabilir.
HTTP safe/idempotent method semantiği application’ın retry contract’ıyla aynı mekanizma değildir. Endpoint adı, bir key header’ı veya transaction tek başına end-to-end exactly-once effect sağlamaz. Email, file ve network effect’i seçilen SQL transaction’ının dışındadır. UNKNOWN response dalı da gerçek socket timeout ölçümü değil, caller bilgisinin kaybını gösteren öğretim olayıdır.
2. Red · Güven ve etki
Hareket olmadan bütün senaryoları oku
Eski revision
- Caller önce version 1’i okudu
ReadVersion=1, caller’ın rename niyetini oluşturduğu kopyanın revision’ıdır. Bu sayı, kayıt sahibinin şimdi de version 1 tuttuğunu söylemez.
- Rename niyeti
- readVersion=1
- Kayıt sahibi
- Current revision henüz okunmadı
- Kabul sözleşmesi
- Update kararı henüz yok
- Kullanımdan önce kayıt version 2
CurrentBeforeUse=2 ve başlık Coffee note. Önceki read’in kopyası güncel kayıt sahibinin revision’ından farklıdır.
- Rename niyeti
- expectedVersion=1
- Kayıt sahibi
- Coffee note / currentVersion=2
- Kabul sözleşmesi
- Revision koşulu gerekir
- Karar ve write aynı statement içinde
Sabit UPDATE statement’ı id ile birlikte version koşulunu da değerlendirir. Eski expectedVersion=1, currentVersion=2 kaydını eşleştirmediğinden write kabul edilmez.
- Rename niyeti
- expectedVersion=1
- Kayıt sahibi
- affectedRowsOnStale=0
- Kabul sözleşmesi
- revision mismatch
- Coffee note korunuyor
After kaydı Coffee note ve version=2 olarak kalıyor. AffectedRows=0, bu guarded update’in uygulanmadığını gösterir; önceki read’in yok olduğunu söylemez.
- Rename niyeti
- readVersion=1
- Kayıt sahibi
- after: Coffee note / version=2
- Kabul sözleşmesi
- Eski revision ile update uygulanmadı
- Parameter binding bu kararın yerine geçmez
Title ve noteId data olarak bind edilir; revision guard ayrıca operation’ın güncel kayıt için geçerli olup olmadığını sınırlar. Data/query ayrımı ile güncellik koşulu farklı soruları cevaplar.
- Rename niyeti
- Parametreler data olarak kalır
- Kayıt sahibi
- affectedRowsOnStale=0
- Kabul sözleşmesi
- Binding != revision agreement
- Sonucu kendi kapsamıyla bildir
Doğrulanan sonuç, eski revision koşuluyla yapılan bu update’in kaydı değiştirmemesidir. Her distributed writer veya başka store için aynı concurrency garantisi çıkarılmaz.
- Rename niyeti
- readVersion=1
- Kayıt sahibi
- Coffee note / version=2
- Kabul sözleşmesi
- Revision koşullu update reddedildi
Parameter farkı
- Operation scope’u sabitle
Caller-demo, rename-public-note purpose’u ve request-a key’i bir arada değerlendirilir. Key’in tek başına bilinmesi caller identity veya permission kanıtı değildir.
- Rename niyeti
- caller-demo / rename-public-note / request-a
- Kayıt sahibi
- Saved result henüz incelenmedi
- Kabul sözleşmesi
- keyIsCredential=false
- İlk operation’ın sonucu kayıtlı
Normal result, tea notunu Updated note ve version=2 olarak kaydetmiş. Bu kayıt, seçilen scope’taki ilk operation’ın parametrelerine aittir.
- Rename niyeti
- title=Updated note
- Kayıt sahibi
- saved result: Updated note / version=2
- Kabul sözleşmesi
- İlk operation parametrelerine bağlı
- Aynı key, farklı title
Yeni aday Different note title istiyor, ama sameScopeKey=true. Aynı key etiketi, farklı parametreleri otomatik olarak aynı operation yapmaz.
- Rename niyeti
- newTitle=Different note title
- Kayıt sahibi
- Kayıtlı sonuç değişmedi
- Kabul sözleşmesi
- sameScopeKey=true
- Parameter conflict kararı
Örneğin sonucu parameter-conflict. Uygulama aynı scope/key için ilk parametrelerle uyuşmayan adayı yeni rename olarak uygulamıyor.
- Rename niyeti
- Yeni parametreler farklı
- Kayıt sahibi
- existingResultPreserved=true
- Kabul sözleşmesi
- outcome=parameter-conflict
- Önceki sonuç silinmedi
ExistingResultPreserved=true, önceki operation sonucunun korunduğunu belirtir. Conflict kaydı rollback edilmiş ilk operation veya silinmiş result anlamına gelmez.
- Rename niyeti
- parameter conflict
- Kayıt sahibi
- Kayıtlı sonuç korundu
- Kabul sözleşmesi
- No second rename accepted
- Yeni iş için yeni sözleşme gerekir
Başka purpose veya farklı parametreler yeni bir operation olabilir; bunların permission ve identity scope’u ayrı değerlendirilir. Idempotency key’i authorization yerine koyamazsın.
- Rename niyeti
- separatePurposeIsSeparateScope=true
- Kayıt sahibi
- Mevcut sonuç korundu
- Kabul sözleşmesi
- keyIsCredential=false
VARSAYIM · SINIR · KONTROL
İlk check’in bilgisi sınırlıdır
Artifact readVersion=1 ile use sırasındaki currentVersion=2’yi ayrı gösterir. Yanlış varsayım eski observation’ın hâlâ current state olduğunu kabul etmektir. Sonuç yeni title’ın eski karar tarafından ezilmesi olabilir. Doğru guard dalında affectedRows=0 ve current state korunur. Öğrenci expected revision’ın hangi authoritative statement’ta değerlendirildiğini ve yanlış eşleşmede ne değişmediğini inceler.
Transaction declaration görmek application invariant’ının bütünüyle kapsandığını söylemez. Başka row, dış effect veya başka data owner aynı boundary’nin dışında kalabilir. Atlas transaction’ı mutation, result ve idempotency record’u birlikte tutar. Bu kapsamı farklı isolation level veya distributed topology’ye taşımadan önce onların condition ve failure davranışları ayrıca değerlendirilir.
UNKNOWN response failed operation değildir
Caller’ın yanıt alamaması ile store’un rollback etmesi farklı sonuçlardır. Commit olmuş iş aynı scope/key/parameters ile tekrar sorulduğunda stored result kullanılabilir. Key’i değiştirmek yeni intent anlamına gelebilir; aynı key’i farklı title veya purpose için kullanmak da contract kararı gerektirir. Idempotency key identity veya permission sağlamaz.
Yalnız success flag saklamak hangi note ve revision’ın tamamlandığını anlatmayabilir. Saved result noteId, title ve revision içerir; parameter conflict bu kaydı değiştirmez. Dış effect için bir sent flag varsa onun hangi owner’ın receipt’ini gösterdiği ayrıca bilinmelidir. Exactly-once iddiası aynı owner ve aynı effect kapsamına bağlanmadıkça sonuçlar karışır.
3. Blue · Güvenli geliştirme ve savunma
Hareket olmadan bütün senaryoları oku
Sonuç bilinmiyor
- Caller’ın ilk sonucu unknown
Before/after revision ve affectedRows, yerel SQLite statement’ı ile ayrı SELECT okuyucusundan gelir; caller’ın UNKNOWN bilgisi ise ayrıca verilen senaryo koşuludur. CallerFirstKnowledge=unknown, caller’ın ilk sonucu öğrenemediğini anlatır. Bu alan, database’de commit olmadığına dair bir sonuç değildir.
- Caller gözlemi
- callerFirstKnowledge=unknown
- Operation sonucu
- Commit henüz incelenmedi
- Kanıt yorumu
- Sonuç kanıtı henüz yok
- Database commit’i ayrı gözlendi
FirstCommitted=true ve kayıtlı result Updated note, version=2. Caller’ın unknown bilgisi ile kalıcı commit aynı anda bulunabilir.
- Caller gözlemi
- callerFirstKnowledge=unknown
- Operation sonucu
- firstCommitted=true / result version=2
- Kanıt yorumu
- Commit != caller receipt
- Retry aynı operation parametrelerini taşıyor
SameParameters=true ve aynı caller/purpose/key scope’u, retry’nin ilk operation ile ilişkilendirilmesini sağlar. Sadece aynı title benzerliği bu ilişkiyi kurmaz.
- Caller gözlemi
- same scope / sameParameters=true
- Operation sonucu
- saved result version=2
- Kanıt yorumu
- Aynı operation ile eşleştirildi
- Kayıtlı sonuç yeniden kullanıldı
ResultReused=true ve mutationCount=1. Retry, ikinci rename yazmadan ilk operation’ın sonucunu kullanmış.
- Caller gözlemi
- retry correlated
- Operation sonucu
- resultReused=true / mutationCount=1
- Kanıt yorumu
- Tek değişiklik gözlendi
- Unknown dalını başarısız sayma
Buradaki kanıt, ilk operation’ın commit edildiğini ve retry’de tekrar effect yaratılmadığını gösterir. Caller’ın önceki unknown durumu “ilk iş başarısızdı” diye değiştirilemez.
- Caller gözlemi
- Caller’ın ilk sonuç bilgisi eksik
- Operation sonucu
- firstCommitted=true / mutationCount=1
- Kanıt yorumu
- Unknown knowledge != failed operation
- Doğrulanan sınırı açık bırak
Bu örnek kaydedilmiş sonucu tekrar kullanır. Dış API effect’leri aynı SQLite transaction’ına katılmaz; local kayıt bütün sistem için exactly-once garantisi değildir.
- Caller gözlemi
- same operation
- Operation sonucu
- mutationCount=1
- Kanıt yorumu
- externalEffectsAtomic=false
Bilinen rollback
- Transaction öncesi revision’ı oku
Before/after revision ve affectedRows, yerel SQLite statement’ı ile ayrı SELECT okuyucusundan gelir; caller’ın UNKNOWN bilgisi ise ayrıca verilen senaryo koşuludur. Rollback fixture’ında beforeVersion=1. Sonraki kayıtları aynı transaction’ın sonucuyla karşılaştırmak için bu başlangıç bilinmelidir.
- Caller gözlemi
- Caller sonucu henüz bilinmiyor
- Operation sonucu
- beforeVersion=1
- Kanıt yorumu
- Transaction sonucu henüz yok
- Result kaydı constraint’e takıldı
Zararsız NOT NULL result adayı başarısız oluyor ve explicit rollback uygulanıyor. Bu, yalnız caller gözleminin eksik olmasından farklı bir transaction sonucudur.
- Caller gözlemi
- Caller sonucu ayrı değerlendirilir
- Operation sonucu
- Constraint hatası / explicit rollback
- Kanıt yorumu
- Rollback gözlendi
- Revision ve result birlikte incelendi
AfterVersion=1 ve resultRecords=0. Önceki revision korunmuş ve bu transaction için committed result bırakılmamış.
- Caller gözlemi
- Caller sonucu ayrı değerlendirilir
- Operation sonucu
- afterVersion=1 / resultRecords=0
- Kanıt yorumu
- Bu transaction’dan committed result yok
- Bu dalın kanıtı rollback’tir
Explicit rollback ile bağımsız after kaydı birlikte bilinen başarısız transaction’ı destekler. Unknown-response dalının firstCommitted=true kaydı bu dala taşınmaz.
- Caller gözlemi
- Başka dal: response sonucu bilinmiyor
- Operation sonucu
- afterVersion=1 / resultRecords=0
- Kanıt yorumu
- Known rollback != unknown commit
- Eksik gözlem üçüncü bir durumdur
Commit veya rollback için gerekli gözlem yoksa iki daldan birini seçemezsin. Selector’ın sıfır eşleşmesi, eksik transaction kaydını tamamlamaz.
- Caller gözlemi
- Eksik sonuç bilinmiyor olarak kalır
- Operation sonucu
- Rollback örneği ayrı doğrulandı
- Kanıt yorumu
- Eksik kanıt başka daldan tamamlanmaz
- Retry kararını bilinen state’e bağla
Saved result varsa aynı operation için onu değerlendir; bilinen rollback’te kalıcı sonuç olmadığını dikkate al; unknown durumunda outcome kanıtı iste. Key possession tek başına bu kararların hiçbirini vermez.
- Caller gözlemi
- keyIsCredential=false
- Operation sonucu
- rollback resultRecords=0
- Kanıt yorumu
- Result / rollback / unknown ayrı tutulur
UYGULAMA · GÜVENLİK KONTROLÜ · DOĞRULAMA
Invariant authoritative statement’ta değerlendirilsin
Before/after revision ve affectedRows, yerel SQLite statement’ı ile ayrı SELECT okuyucusundan gelir; caller’ın UNKNOWN bilgisi ise ayrıca verilen senaryo koşuludur. Atlas invariant’ı title’ın yalnız current revision expected revision’a eşitken değişmesidir. Expected=1/current=2 mismatch rowcount=0 üretir ve yeni title/revision korunur. Before/after değerleri independent SELECT ile karşılaştırılır; UI kopyasının kendiliğinden güncellendiği varsayılmaz. Transaction visibility ve operation condition ayrı kontrollerdir.
Örnek explicit transaction control ve iki independent connection kullanır. Daha geniş invariant için row set, condition veya locking semantics ve failure handling seçilen database’in contract’ına göre belirlenir. Tek row üzerinde gözlenen doğru davranış başka owner veya external effect için atomicity kanıtı değildir.
Mutation ile saved result birlikte commit edilsin
Caller-demo / rename-public-note / request-a scope’u normalized tea ve Updated note parameters’ını saklar. Normal response ile aynı-parameter retry aynı result’u döndürür; mutationCount=1 kalır. Alias bu öğretim kaydındaki request kimliğidir, credential değildir. Başka purpose için aynı key farklı namespace’e ait olabilir; aynı purpose içinde parameter mismatch ise ayrı conflict’tir.
Rollback dalında note eski revision’da kalır ve result record oluşmaz. UNKNOWN response dalında commit korunur ve retry saved result’u bulur. İkisinde caller yeniden işlem yapmak isteyebilir ama bilinen business state farklıdır. Retry policy bu farkı korumalıdır; browser receipt veya external effect gözlenmemişse bunların sonucu ayrıca UNKNOWN kalır.
ŞİMDİ VAKAYA UYGULA
Eski revision, tekrar gelen operation ve bilinmeyen sonuç hangi kanıtlarla ayrılır?
Duru, Atlas public tea notunun başlığını değiştirmek istiyor. Uygulama revision koşulunu ve caller/purpose/key ile bağlı operation kaydını ayrı değerlendiriyor. Bir sonuç caller’a görünmese bile database’de commit edilmiş olabilir.
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 condition/retry result ledger
Bir alan seç; hangi sonucu desteklediğini ve nerede yetersiz kaldığını incele.
Ham kaydı ve alan açıklamalarını oku
{
"invariant": {
"noteId": "tea",
"readVersion": 1,
"currentBeforeUse": 2,
"affectedRowsOnStale": 0,
"after": {
"title": "Coffee note",
"version": 2
},
"statement": "UPDATE notes SET title=?,version=version+1 WHERE id=? AND version=?",
"parameters": [
"Updated note",
"tea",
1
]
},
"scope": {
"callerAlias": "caller-demo",
"purpose": "rename-public-note",
"keyAlias": "request-a",
"parameters": {
"noteId": "tea",
"title": "Updated note"
},
"keyIsCredential": false,
"separatePurposeIsSeparateScope": true
},
"normal": {
"result": {
"noteId": "tea",
"title": "Updated note",
"version": 2
},
"mutationCount": 1,
"resultRecords": 1
},
"retryUnknown": {
"firstCommitted": true,
"callerFirstKnowledge": "unknown",
"sameParameters": true,
"resultReused": true,
"result": {
"noteId": "tea",
"title": "Updated note",
"version": 2
},
"mutationCount": 1
},
"mismatch": {
"sameScopeKey": true,
"newTitle": "Different note title",
"outcome": "parameter-conflict",
"existingResultPreserved": true
},
"rollback": {
"beforeVersion": 1,
"afterVersion": 1,
"resultRecords": 0,
"reason": "benign NOT NULL result candidate; explicit rollback"
},
"limits": {
"concurrentRequestsExecuted": false,
"unknownResponse": "injected caller knowledge event, not socket loss",
"externalEffectsAtomic": false,
"universalExactlyOnce": false
},
"selector": {
"language": "XPath",
"xml": "<audit><revision expected=\"1\" current=\"2\" mutationAccepted=\"false\"/></audit>",
"xpath": "count(/audit/revision[@expected != @current and @mutationAccepted='true'])",
"expected": 0,
"positiveFixtureXml": "<audit><revision expected=\"1\" current=\"2\" mutationAccepted=\"true\"/></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."
}
}- invariant
- Fixed guarded SQL ve observed stale rejection.
- scope
- Caller/purpose/key ile normalized parameters.
- retryUnknown/rollback
- Commit korunması ile rollback ayrı outcomes.
- selector
- Synthetic stale mutation acceptance kararı.
Selected own SQLite +finite sequential public-note operations. Vulnerable reproduction, concurrency harness, actual network loss veya external side-effect guarantee yok.
İki yanlış kanı
Transaction açtım; application’ın bütün races’ı ve invariants’ı çözülmüştür.
Isolation/operation predicate/row scope ayrı seçimlerdir; transaction declaration tek başına correct business condition değildir.
Response gelmedi; operation kesin rollback oldu.
Caller knowledge unknown kalabilir; committed result same-scope retry’de reused olabilir, rollback ayrı kanıt ister.
SIRA SENDE
Bu hikâyeyi sen çöz.
Sonucu tahmin et, kanıtın sınırını bul ve nedenini kendi cümlenle anlat.
Read sırasında version=1, kullanım anında current version=2. UPDATE version=1 koşuluyla çalışıyor. Yeni title yazılır mı?
- Evet. Bir kez read edilmiş olması sonraki bütün state değişikliklerini kilitler.
- Hayır. affectedRowsOnStale=0; Coffee note version=2 korunur.
Gerekçeli cevabı oku
Hayır. affectedRowsOnStale=0; Coffee note version=2 korunur. — Version koşulu write sırasında yeniden uygulanır. Eski read sonucu güncel kaydın üzerine yazma izni değildir.
Caller ilk sonucu bilmiyor, fakat ilk işlem commit etmiş. Aynı scoped key ve parametrelerle retry neden ikinci mutation üretmiyor?
Dersten seçilen artifact alanları; öğretim örneği
- retryUnknown.firstCommitted
- true
- retryUnknown.callerFirstKnowledge
- unknown
- retryUnknown.sameParameters
- true
- retryUnknown.resultReused
- true
- retryUnknown.mutationCount
- 1
- Önceki result yeniden kullanılır; mutationCount=1 kalır.
- Caller unknown dediğinde server bütün önceki write’ları geri alır.
Gerekçeli cevabı oku
Önceki result yeniden kullanılır; mutationCount=1 kalır. — callerFirstKnowledge=unknown, server commit’inin yokluğu değildir. Same-parameter dedupe, korunmuş sonucu döndürür ve effect’i tekrar uygulamaz.
Aynı scope/key farklı title ile gelince parameter-conflict oluşuyor. Idempotency scope, transaction ve gerçek concurrency için hangi sınırlar korunmalı?
Gerekçeli cevabı oku
Key caller, purpose ve parametrelerle aynı işlemi tanımlar; farklı title eski result’un üzerine yazılmaz. Key credential veya authorization değildir. Yerel transaction write ve result record’u birlikte koruyabilir; başarısız result adımında explicit rollback gerekir. Bu sıralı örnek parallel request isolation veya external effect atomicity ölçmez; universal exactly-once garantisi vermez.
□ Idempotency key’ini purpose/parametrelerine bağladım; permission saymadım.
□ Yerel result reuse’dan concurrency veya external atomicity garantisi çıkarmadım.
Uygulama konsolunu aç · request / response / browser
Request, URL, cookie ve DOM örneklerini ayrıca aç
Kaynaklar ve kapsam
- MITRE CWE-367 — TOCTOUDescription · Potential Mitigations
- SQLite — Transaction2. Transactions · 2.1. Read transactions versus write transactions · 2.2. DEFERRED, IMMEDIATE, and EXCLUSIVE transactions · 2.3. Implicit versus explicit transactions
- SQLite — IsolationIsolation Between Database Connections · Isolation And Concurrency
- 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
- Stripe — Idempotent requestsIdempotent requests: stored status/body · Parameter comparison and key retention · Validation/concurrent request exclusions
- Amazon Builders Library — Making retries safe with idempotent APIsRetrying and side effects · Retries and semantic equivalence · Late arriving requests · Same client request ID, different intent