Yazılım Mimarileri ve Tasarım Desenleri Üzerine

Outbox Design Pattern Nedir? Nasıl Uygulanır? (Inbox Pattern Eşliğinde)

Merhaba,

Günlük yaşamda gurbet ellerde bulunan bir yakınınıza hatıra dolu bir mektup yazıp göndermek istediğiniz olmuştur. Mesela böyle bir istek karşılığında ne yapardınız hiç düşündünüz mü? Muhtemelen, mektubu kaleme aldıktan sonra zarflayıp, gönderilecek adres bilgisi eşliğinde postaya bırakırdınız ve ardından gerisi posta memurlarının iş planlamasına kalacağından dolayı unutarak günlük rutininize dönerdiniz. Öyle değil mi? Gönderdiğiniz mektubun, varış noktasına ne şekilde hangi yöntemlerle ne kadar zamanda varacağı sizi pek ilgilendirmezdi ve hatta mektubun bir gün alıcıya vardığında belki size geri dönüp dönmeyeceğini bile önemsemeksizin yaşamanıza devam ederdiniz. Gayet doğal… Lakin göndermek istediğiniz mektubu bırakacağınız posta teşkilatının çalışmadığı bir döneme denk geldiğini düşünürseniz eğer vaz mı geçerdiniz? Hayır dimi! Bu gün çalışmayan posta teşkilatı elbet yarın belki yarından da yakın çalışır diye mektubu elinizde tutar ve ne zaman teşkilat faal olur o zaman gider mektubu postaya emanet ederdiniz.

Buradaki varsayımdan şöyle bir sonuç çıkarabiliriz; yaptığınız iş her ne kadar sizden çıksa da bütünsel olarak nihayetlenmediği sürece işin sorumluluğundan kurtuldunuz anlamına gelmemektedir. Siz mektubu yazmış olabilirsiniz ama bazen posta teşkilatına emanet etmek için de sabretmeniz gerekebilir. (Yılmaz komutanımın değimiyle iş her ne kadar sizden çıksa da o işin öldüğünden emin olmanız ve gerekirse sizin öldürmeniz gerekmektedir!) Nasıl ki, -ben mektubu yazdım ama posta teşkilatı çalışmadığı için gönderemedim- demek doğru bir mazeret değilse, dağıtık mimarilerdeki servisler arası iletişim süreçlerinde kaybolan mesajlar açısından -‘A’ servis göndermiş ‘B’ servis ayakta olmadığı için veriyi alamamış- şeklinde bir durumda mazeret değildir. Ne de olsa, ‘A’ servisin ilgili mesajı üretmesi kadar ‘B’ servise eriştirmesi de onun sorumluluğundadır.

Şimdi gelin buradaki beşeri örnek üzerinden sadede gelelim ve sunulan davranışı yazılımsal açıdan metafor ederek modelleyip, konumuz olan Outbox Design Pattern’a girizgâh eyleyelim.

Outbox Design Pattern Nedir?

Outbox pattern, Guaranteed Delivery Pattern(Garantili Teslimat Deseni)’a dayanır!

Asenkron iletişim kuran sistemlerde, servisler arası(ya da servis ile message broker arası) iletişim süreçlerinde gönderilen mesajların yerini bulamadan bağlantının kopması, hata alınması ve süreçte beklenmeyen fiziksel yahut yazılımsal kesintilerin meydana gelmesi (vs.) durumlarına istinaden olası veri kayıplarına ve verisel açıdan servisler arası tutarsızlıklara mahal vermemek için mesajın kaybolmasını engelleyerek, yaşanan olumsuz durumun/durumların geçmesi üzerine bağlantının tekrardan kurulması durumunda hedef noktaya mesajın tekrardan gönderilmesi için devreye giren basit ama kritik noktalarda muazzam etkili bir pattern’dır.

Outbox Design Pattern’ın Teorik Davranışı Nasıldır?

Şema Kaynağı : https://github.com/obsidiandynamics/goharvest

Outbox pattern’ı teoride anlatabilmek için yukarıdaki şemadan istifade edebiliriz. Bir servise gelen istek üzerine yapılan işlemler neticesinde farklı bir servise yahut bir message broker’a yeni bir message/event publish edileceğini düşünelim. Bu işlem ihtiyaç anında gerçekleştirilirse eğer gönderilen mesajın hedef servise yahut message broker’a vardığından emin olmalı, eğer ki bir problem söz konusu olursa bu servisin de yaptığı tüm işlemler bütünsel tutarlılık için geri alınmalıdır(Bknz : Compensable Transaction). Ama bu ne kadar doğru olacaktır? Nihayetinde distributed bir mimaride bazen servislerin geçici süreliğine problem yaşaması oldukça normal bir durumdur. İlgili servisin ayağa kalkana kadar işlenecek verilerin/mesajların/event’lerin tutulması ve servis ayağa kalktığı zaman bunların işlenmesi en ideal olanıdır! Bizler yapılan işlemleri geri almak yerine bu davranışı tercih etmek istiyor olabiliriz. Aksi taktirde yapılanların geri alınmaması ciddi manada veri tutarsızlığına sebebiyet verecektir. Yukarıdaki şemaya göz atarsanız eğer ilgili servisin gelen istek neticesinde görevini tamamladığı ve artık işleyişin devamı için farklı bir servise olayı fırlatması gerekmektedir. Bunu yaparken hedef servis türlü sebeplerden dolayı ayakta değilse eğer bu serviste yapılan işlemler bütünsel açıdan tutarsızlık arz edecektir. İşte böyle bir durumda dış servis yahut message broker ile iletişim işlemini direkt yapmak yerine ilgili message/event’i giden kutusuna(Outbox) karşılık gelecek olan bir tabloya işleyip bekletmekte fayda vardır. Ardından düzenli aralıklarla bu tabloyu tarayan ve orada kayıtlı olan message/event’leri hedef noktaya publish edecek olan ‘Outbox Publisher Application’ aracılığıyla ilgili message/event’ler alıcı servislere iletilmeye çalışılır. Böylece mimari tasarımı açısından, servisler arası iletişim süreci alıcı servisin yahut message broker’ın ayakta olup olmaması durumuna göre olası veri kayıpları riskinden arındırılarak daha ehemmiyetli olması sağlanacak ve mesajın en az bir kere hedefe varacağı garanti altına alınarak neticede servisler arası loosely coupled(gevşek bağlılık) konusunda bir adım daha atılmış olunacaktır.

Sevisler arası iletişim süreçlerinde kaybolan mesajlar birçok geliştiricinin uykusunun kaçırmasının temel kaynağıdır! O yüzden bu konu ciddi kritik arz etmektedir!

Nihayetinde bakarsanız eğer asenkron süreçte servisler arası iletişim verilerinin Outbox’da tutularak; olası aksaklıklardan, sistem kesintilerinden veya bağlantı kopukluklarından dolayı oluşabilecek iletişim ve veri transferi problemlerinden etkilenmemesi sağlanarak bütünlüğün korunması amaçlanmaktadır.

İçeriğimize girizgâh eylediğimiz mektup misaliyle bu durumu karşılaştırırsak eğer; siz ve yakınınız iki servise, mektup ise aranızdaki iletişim sürecindeki mesaj yahut event’e ve posta ise message broker’a karşılık gelmektedir. Outbox’ın ise sizin yakınınıza göndermek istediğiniz mesajın(mektubun) posta memurlarına verilip verilmediğinin garantisini sağlayan bir kontrol mekanizması olduğunu düşünebilirsiniz.

Outbox pattern sayesinde servisler arasındaki iletişim süreçlerinde mesajların nihai olarak başarılı bir şekilde hedef servis(ler)e iletildiğinden emin olabilir ve veri tutarsızlığına karşı bütünsel açıdan önleyici bir davranış sergilediğinizin bilinciyle gönül rahatlığıyla çalışmalarınıza devam edebilirsiniz.

Outbox pattern distributed mimarilerde atomik bir davranış sergilenmesini sağlar.

Outbox pattern’ı daha iyi anlayabilmek için Microservice Mimarilerde Saga Pattern İle Transaction Yönetimi başlıklı makalemde teorik olarak değindiğim distributed transaction kavramını ve bu kavramın uygulanabilir olması için gerçekleştirilen belli başlı teknikleri bilmeniz gerekmektedir. İşte tüm bunlar bir yana Outbox pattern sayesinde distributed transaction tekniklerini uygulamaya gerek kalmaksızın mesajları diğer servislere erişim güvenilirliğini sağlayarak gönderebilir ve böylece uygulama bütünlüğü açısından pratik olacak şekilde daha emin adımlarla veri tutarlılığını sağlayabilirsiniz.

Microservice yaklaşımlarında, kritik mesajlara sahip olan her bir servis kendi Outbox tablosuna sahip olmalı ve mesajları önce bu tabloya atıp ardından bir publisher aracılığıyla hedef servise ya da message broker’a göndermelidir.

Outbox Pattern Hangi Durumlarda Kullanılır?

Outbox pattern yukarıdaki satırlarda vurguladığımız gibi bir servis tarafından mesajlar/event’ler yayınlandığı esnada doğrudan hedef servise yahut message broker’a göndermek yerine bu mesajları bir veritabanı tablosuna kaydederek ardından bir publisher aracılığıyla belirli zaman aralıklarında veya CDC(Change Data Capture) aracılığıyla hedef servislere iletmeyi amaçlayan bir pattern’dır.

Buradan anlaşılıyor ki, servislere ya da message broker’a gönderilecek mesaja dair en az bir kere iletme garantisini sağlamak istiyorsanız eğer Outbox pattern kullanılabilir.

Özellikle bir serviste aynı anda iki işlemin yapıldığı durum söz konusuysa Outbox pattern biçilmiş kaftan olacaktır. Buna herhangi bir e-ticaret uygulamasından küçük bir kesiti misal olarak sunarsak eğer; ‘Order Service’ üzerinde, kullanıcıdan gelen sipariş üzerine hem ‘Orders’ tablosuna bir kayıt atıldığını hem de siparişin oluşturulduğuna dair ‘OrderCreatedEvent’ isimli bir event’in message broker’a yazıldığını tahayyül edelim… Bir servis yaptığı işlemler sürecinde bunun gibi iki farklı yapıya(veritabanı-message broker) dair kalıcı işlem gerçekleştiriyorsa eğer bu durumu Dual Write olarak nitelendiriyoruz.

Belirli bir olay meydana geldiğinde hem veritabanına hem de bir message broker’a aynı anda veri yazma işlemine Dual Write denir.

İşte, Dual Write durumunun söz konusu olduğu anlarda veritabanına kaydın atılıp message broker’a gönderilememesi yahut bunun tam tersi gibi aksilikler meydana gelirse eğer burada hem o olayın yaşandığı servis hem de message broker’ı dinleyen diğer servis(ler) için ciddi verisel farklar yaratabileceğinden dolayı uygulama bütünlüğü açısından tutarsızlıklar söz konusu olabilir. Eee Dual Write’tan kaynaklanabilecek bu tutarsızlıklar sistem sağlıklıyken ortaya çıkmayabilir yahut fark edilmesi oldukça güç olabilir ancak uzun vadede mutlaka kendilerini gösterecektirler. İşte bu olası tutarsızlıkları sıfır ihtimale indirgeyebilmek için Outbox pattern hayati bir rol üstlenebilir. Outbox pattern, veritabanında yapılacak değişikliğin ardından yürütülecek olan işlemleri, veritabanı içerisinde bir görev olarak saklama temeline dayanır. Böylece bir transaction içerisinde hem veritabanında yapmak istediğimiz işlemi gerçekleştiriyor hem de bu işlemden sonra yürüteceğimiz aksiyon için işaret bırakmış oluyoruz.

Unutmayın!
Dual Write; distributed, event based vs. gibi uygulamalarda sıklıkla sorunlara neden olan bir durumdur. Ve bu sorunları tespit edebilmek, maliyetleri ölçebilmek ve düzeltebilmek oldukça zor ve zahmetli olacaktır!

Outbox pattern Dual Write durumu varsa düşünülmelidir!

Outbox Pattern vs Event Sourcing

Yukarıdaki satırlar sizlere Event Sourcing‘i anımsatmış olabilir. Nihayetinde yapılacak işlemlere dair(publish/subscribe) bir tabloda tutulacak kayıtlar söz konusudur. Evet, Outbox pattern deyince akla event sourcing’in gelmesi normaldir lakin Outbox pattern event sourcing değildir. Belki alternatifidir diyebiliriz ama değildir! Outbox pattern ile event sourcing arasındaki en radikal farkı ele almamız gerekirse eğer; event sourcing’de bir işlenen veriye dair tüm olaylar kayıt altına alınırken, Outbox’da ise işlenecek olan mesajların/event’lerin işlendikten sonra silinmesi ya da işlendiğine dair güncellenmesi söz konusudur. Event sourcing’de kesinlikle herhangi bir olayın silinmesi söz konusu değildir bilakis bir veriye dair yapılan bir işlemin geri alınması bile yine ayrı bir olay olarak kabul edilmekte ve böylece meydana gelen olayların bütünü ilgili verinin nihai halini ortaya sermekte ve süreçte de ne gibi değişimler yaşadığını bizlere söylemektedir.

Outbox pattern ile ilgili en önemli husus yalnızca geçici bir mesaj/olay deposu olmasıdır. Mesajlar hedef servise ya da message broker’a ulaştırıldığı taktirde ya silinmeli ya da işlendiğine dair güncellenmelidir.

Outbox Pattern’da Mesajlar Nasıl Publish Edilmelidir?

Outbox pattern ile Outbox tablosuna kaydedilen mesajları/event’leri publish etmenin makul olan iki farklı yolu vardır diyebiliriz;

Outbox Pattern’ın Kullanılacağı Örnek Senaryo Bileşenleri Neler Olabilir?

Outbox pattern’ın hangi durumlarda kullanılacağını yukarıdaki satırlarda Outbox Pattern Hangi Durumlarda Kullanılır? başlığı altında değerlendirmeye çalışmıştık. Burada ise bahsedilen durumları yaşayabileceğimiz senaryolara birkaç örnek vermek faydalı olacaktır kanaatindeyim;

vs. gibi tüm senaryolarda Outbox pattern ile yapılacak işlemin devamını kayda alabilir ve veri kaybını önceleyecek şekilde bir publisher eşliğinde diğer işi üstlenen servis yahut message broker ile iletişim kurabilirsiniz.

Outbox Pattern’ın Idempotents Sorunsalı!

Outbox pattern’de, publish edilen mesajların ya da event’lerin işlendiğine dair işaretlenmesine yahut tablodan işlenenlerin silinmesine rağmen düşük ihtimalde olsa bir handikap söz konusu olabilir. Bu handikap, mesajlar işlendikten/publish edildikten sonra sıra Outbox table üzerinde işaretlenmeye yahut ilgili mesajın silinmesi işlemine gelindiğinde ilgili veritabanı ile oluşabilecek bir olası iletişim hatası nedeniyle bu işlemin gerçekleştirilememesidir. Evet, mesaj yayınlanmıştır ama bu yayınlama neticede Outbox table’a yansıtılamamıştır. Böyle bir durumda Outbox table’ın bulunduğu veritabanı ile tekrar iletişim kurulduğunda işlenmiş olan mesaj tekrardan işleme tabi tutulacak ve uygulama açısından bütünsel tutarlılığı sarsabilecek bir durum meydana gelebilecektir. İşte şimdi Peki bu duruma karşı nasıl bir davranış sergilememiz gerekmektedir? sorusu akıllara gelmektedir…

Bu duruma istinaden mesajları/event’leri tüketen consumer’ların Idempotents olarak tasarlanması bu olası hatayı ortadan kaldıracaktır.

Idempotent; matematik ve bilgisayar bilimlerinde kullanılan ve ilk işlem haricinde sonraki tüm işlemler için etkisi söz konusu olmayan ve sonucu değiştirmeden uygulanabilen bir özelliği ifade eden terminolojik bir terimdir. Matematiksel olarak f(f(x)) = f(x) şeklinde formülüze edilebilir.

Idempotent’e matematiksel örnek olarak mutlak değeri verebiliriz. Nihayetinde mutlak değerin amacı bir sayının sıfıra olan uzaklığını ölçmek olduğu için |n| ile |-n| işlemlerini ne kadar değerlendirirsek değerlendirelim, bu iki ölçümde sonuç açısından herhangi bir fark hiçbir zaman söz konusu olmayacaktır.

Idempotent kavramına biz yazılımcıların anlayacağı dilden daha farklı örnekler verebilmemiz açısından rest mimarisi üzerinden de bir metafor gerçekleştirebiliriz. Rest mimarisinde; get, put ve delete action’ları idempotent iken, post metodu idempotent değildir! Çünkü get, put ve delete her ne kadar tekrarlı tetiklenirse tetiklensinler yaptıkları ilk işlemin dışında ekstradan sonuç üretemezler. Yani örnek olarak, ‘3’ id değerine sahip bir kullanıcıyı silmek(delete) istiyorsanız eğer bunu ilk istekte gerçekleştirir, sonraki isteklerde ise ‘3’ id değerine karşılık bir kullanıcı olmayacağından dolayı ekstradan bir sonuç üretecek işlem gerçekleştiremezsiniz. Veya update products set name='abc' sorgusunu ilk çalıştırdığınızda tüm ürünlerin adı ‘abc’ olacak sonraki tetiklemelerde ise bu sorgu bir değişikliğe yol açmayacaktır. İşte bundan dolayı bu üçü idempotent özellik sergilemektedir. Amma velâkin, adı ‘Hilmi’ olan bir kullanıcıyı eklemek(post) isterseniz her istek gönderdiğinizde adı ‘Hilmi’ olan bir kullanıcı eklenecektir. Bu da sonucu etkileyecektir. Çünkü ilk istekte adı ‘Hilmi’ olan kullanıcı sayısı n iken, beşinci istekte n + 5 olacaktır. Haliyle post action’ı netice itibariyle veritabanı üzerinde işlemden önceki son hale nazaran değişiklik/fark meydana getireceği için idempotent özellik göstermeyen bir fonksiyondur.

Onca örneğin yanında bir de günlük hayattan bir misalde bulunalım isterim. Diyelim ki X bankasının bankamatiğine gittiniz ve bakiyenizi görmek istediniz. İşte bu işlem bir idempotent işlemdir. Nihayetinde bankamatik üzerinden hesabınızdaki bakiyeyi görme işlemini ne kadar yaparsanız yapın sonuç değişmeyecektir. Lakin aynı hesap üzerinden para çekme ya da para yatırma işlemi yapmanız idempotent olmayan bir işlemdir. Çünkü yapılan her bir işlem neticesinde bakiye değeri değişecektir.

Yukarıda verilen örneklerden yola çıkarak konumuz olan distributed yapılanmalarda idempotent davranışını genellersek eğer, bir mesaj birden çok kez yayınlansa dahi consumer’lar açısından aynı etkiye sahip bir işlevsellikte olması gerekmektedir. Bu durum da bir mesajın herhangi bir soruna yol açmaksızın güvenlice yeniden gönderilebileceğini ifade edebiliriz.

Distributed mimarilerde, servisler arası yayınlanacak mesajların yahut event’lerin idempotent olarak tasarlanması doğru ve tutarlı davranış için gerekli olandır.

Peki, yayınlanacak mesajlarda idempotency’yi başarmanın yolu nedir?
Bunun için publish edilecek olan her bir mesaj yahut event için özel bir anahtar, token veya id gibi değer üretilmeli ve böylece consumer’lar tarafından bu mesaj daha önceden tüketilmiş mi? tüketilmemiş mi? ayırt edilebilir bir nitelik kazandırılmalıdır. Bunu şöyle örneklendirebiliriz;Yukarıdaki görsel şemayı incelerseniz eğer Outbox table’a kayıt atılan verilere bir ‘IdempotentToken’ değeri eşlik etmektedir. Bu şekilde publisher ile message broker’a gönderilen mesajlar consumer tarafında işlenirken öncelikle ‘Inbox Table’ adını verdiğimiz bir tabloya işlenmeli ardından process edilmelidirler. Inbox table’da eğer ki aynı ‘IdempotentToken’ değerine sahip bir kayıt varsa işlem gerçekleştirilmemeli, eğer yoksa process edilmelidir. Burada kullanılan yöntem özünde Inbox Pattern‘ı barındırmaktadır.

Inbox Pattern
Outbox pattern’ın akrabası olan bir pattern’dır diyebiliriz 🙂 Outbox pattern’da işlemler(algoritmalar) gerçekleştirilip, yayınlanacak mesajların zemini oluşturulduktan sonra Outbox table’a kaydedilip ardından bir publisher aracılığıyla yayınlama işlemi gerçekleştirilirken, Inbox pattern’da ise işlenecek(algoritması gerçekleştirilecek) mesajlar önce Inbox table’a eklenip ardından process edilirler. Misal olarak; gelen siparişi veritabanına kaydedip ardından stok bilgisinin güncellenmesi için Outbox table’a bu siparişle ilgili bir kaydın oluşturulup publisher ile message broker’a gönderilmesi Outbox pattern iken, stok bilgilerini güncellemekten sorumlu consumer’ın ilgili message broker’dan bu mesajları alıp önce Inbox table’a işleyip ardından process’e tabi tutması Inbox Pattern’dır. Tabi burada işlenen mesajların Inbox table’da nihai olarak tamamlandığına dair güncellenmesi gerekmektedir.

Bazı consumer’lar davranışları itibarıyla varsayılan olarak idempotent’tirler.

Outbox Table’ın Şeması Nasıl Olmalıdır?

Outbox table’ın yapısını oluşturabilmek için aşağıdaki gibi bir tasarımda bulunmak yeterlidir kanaatindeyim.

CREATE TABLE [dbo].[OutboxTable]
(
	[OccuredOn] [datetime2](7) NOT NULL,
	[ProcessedDate] [datetime2](7) NULL,
	[Type] [nvarchar](max) NOT NULL,
	[Payload] [nvarchar](max) NOT NULL,
	[IdempotentToken] [uniqueidentifier] NOT NULL
)

Bu tablodaki kolon yapısını izah etmemiz gerekirse eğer;

Outbox Pattern’ı Pratikte Örneklendirelim

Şimdi bu içeriğimizin en kritik noktasına gelmiş bulunuyoruz. Outbox pattern’ı pratikte ele alabilmek için örneklendiriyor olacağız. Tabi bunun için Onion Architecture altyapısında bir çalışma sergileyecek ve mesajların publish edilmesi için makale sürecinde bahsettiğimiz Pulling Publisher ve Transaction Log Tailing yöntemlerini teker teker uygulayıp, örneklendireceğiz. Ayrıca örneklendirme sürecinde yine önceki satırlarda bahsettiğimiz Inbox Pattern‘ı da uygulayarak olması gereken bir altyapıyla somut bir örnek ortaya koymuş olacağız.

Örneklendirme sürecinde senaryo olarak genel e-ticaret süreçlerindeki basit bir sipariş alma ve stok güncelleme işlemlerini ayrı servisler şeklinde Outbox pattern eşliğinde ele alıyor olacağız.

O halde buyrun başlayalım…

İşte bu kadar 🙂

Test Edelim

Şimdi yaptığımız bu çalışmayı test edebiliriz…
Bunun için kıssadan hisse yaparak SQL sorgularından istifade edeceğiz.

Aşağıdaki sorgu ile hem ‘Orders’ hem de ‘OrderOutboxes’ tablolarına eşzamanlı olarak 10000 kayıt atılabilmektedir.

DECLARE @i INT = 0
WHILE @i < 10000
BEGIN
	DECLARE @id UNIQUEIDENTIFIER = NEWID()
	INSERT Orders(Id, Description, Quantity) VALUES(@id, 'sipariş - ' + CAST(@i as NVARCHAR(MAX)), @i * 2)
	INSERT OrderOutboxes(OccuredOn, Payload, Type, IdempotentToken) VALUES(GETDATE(), '{"Id":"' + CAST(@id as NVARCHAR(MAX)) + '","Quantity":0,"Description":"sipariş - ' + CAST(@i as NVARCHAR(MAX))+ '"}', 'OrderCreatedEvent', NEWID())
	SET @i = @i + 1
END

Yukarıdaki sorgu çalışırken bir yandan da ‘ProcessOutboxJob.Service’ ve ‘Stock.API’ uygulamaları ayakta olduğu taktirde aşağıdaki sorgular eşliğinde görseldeki gibi tutarlı mesajlaşma sürecini gözlemleyebiliriz.

SELECT * FROM Orders
SELECT * FROM OrderOutboxes 
WHERE ProcessedDate IS NULL
SELECT * FROM OrderInboxes

Ara ara ‘OrderOutboxPublishJob’ sınıfındaki update operasyonunu kaldırıp süreci devam ettirirsek eğer Outbox table’da işlendiği halde hala güncellenmeyen kayıtların kaldığını göreceksiniz. Bu kayıtların sonraki süreçte tutarsız herhangi bir işleme maruz kalmaksızın başarılı bir şekilde kaldırılacağını gözlemleyebilirsiniz. Eğer ki tutarsızlık olduğunu düşünüyorsanız aşağıdaki SQL sorgusu ile ‘Orders’ ve ‘OrderInboxes’ tabloları arasındaki farkları görebilir ve süreçte hangi verilerde tutarsızlık olabileceğini verisel açıdan monitör edebilirsiniz.

SELECT * FROM Orders
LEFT JOIN OrderInboxes
ON Orders.Id = OrderInboxes.OrderID
WHERE OrderInboxes.OrderID IS NULL

Yukarıdaki sorgu neticesinde gelen veriler olursa eğer aşağıdaki sorgu ile de Outbox table’da ki halini tarayıp rahatlıkla son durum hakkında bilgi edinebilirsiniz.

SELECT * FROM OrderOutboxes 
WHERE IdempotentToken = '80A716BA-6549-4A26-AD89-59D0FF63D87D'

Nihai olarak;
Outbox pattern ile distributed sistemlerdeki iletişim sürecinde tahaahhüt edilebilmesi zor olan işlemleri daha garantili hale getiriyor ve hatta akrabası olan Inbox pattern desteğiyle de süreçte işlenen veriler üzerinde garanti seviyesini bir tık daha ileri taşıyoruz. Yapısal olarak Outbox pattern’ın ihtiyaç noktalarında oldukça elverişli ve hayat kurtaran ama bir o kadar da zahmetli mimarisi olduğunu görmüş olduk. Bu içeriğimizde değinmemiş olsak da Outbox table’a veri eklenecek tüm eylemleri ihtiyaç noktalarında değil de notification yapılanmalarıyla koordine etmeye çalışmak mimarisel açıdan daha şık bir davranış sergilememizi sağlayacaktır kanaatindeyim. Bunuda sizlere bir fikir olması temennisiyle sunup içeriğimi noktalıyorum.

Üşenmeden okuyup, eşlik ettiğiniz için teşekkür ederim.

İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…

Not : Örnek çalışmayı aşağıdaki github adresinden inceleyebilirsiniz.
https://github.com/gncyyldz/Outbox-Design-Pattern-Example

Mobil sürümden çık