Outbox & Inbox Pattern

Umut Yılmaz
DeFacto Teknoloji
Published in
3 min readNov 24, 2023

Çalıştığım şirketteki monolit yazılmış projede transactional işlemler bolca kullanılmaktaydı. Bununla beraber mikroservis dönüşümü ile birlikte kullandığımız kuyrukların izlenebilir olması da gerekiyordu.

Bu aşamada uyguladığımız OutBox & Inbox Pattern’den bahsetmek isterim.

Outbox Pattern

Service-X, transaction içerisinde işlemlerimizi yapan servisimiz olsun. Bu transaction içerisinde başka servislere de işlem yaptırılması gerektiğini düşünelim. Eğer transaction rollback olursa, başka servislere yaptırdığımız işlemleri geri aldırmamız gerekecektir. Bu da her servisin, bir rollback servisinin de olması anlamına geliyor.

Buradaki rollback servislerinin development maliyetlerine girmemek için farklı bir yaklaşım sergileyebiliriz.

Özetle, transaction içerisinde, başka servisleri de çağırmak gerekiyorsa, bu requestleri, mevcut transaction içerisinde veritabanında saklayabiliriz. Transaction commit olduktan sonra bu requestleri kullanarak ilgili servisi tetikleyebiliriz. Eğer transaction rollback olursa elimizde bir request olmayacağı için başka bir servisi tetiklemek de gerekmeyecektir.

Böylece servislerde rollback methoduna da ihtiyacımız olmayacaktır. Yanı sıra projelerimizde kullandığımız kuyruk yapılarının izlenebilirliğini de arttırmış oluruz.

Kullandığımız kuyruk yapısında servisler, response olarak 2xx dönerken gönderdiği “Status” alanı ile mesajın silinmesini , tekrar denenmesini ya da başarılı bittiğini belirtebilir.

OutBox Flow Chart
  1. Transaction içerisinde, başka servisin kuyruğuna gönderilecek requesti veritabanına kaydediyoruz.
  2. Transaction commit olursa, kuyruğa bir mesaj bırakıyoruz.
  3. Kuyrukta, requestin aynı anda 2 kere işlenmemesi için cahce de bir key saklıyoruz.
  4. Request için yapılacak işlemin başarılı/başarısız olması durumuna göre veritabanındaki durumunu güncelleyip response dönüyoruz.
  5. Her istek kuyrukta 3 kere deneniyor. Hepsi başarısız olursa kuyruktan siliniyor.

Inbox Pattern

Gelen requesti bir kuyruk yapısına publish yapıp response dönen bir servisimiz olsun. Publish yapılan mesajların işlenip işlenmediklerini takip edebilmek için inbox pattern kullanabiliriz. Temel mantık olarak outbox patterne benzetebiliriz.

Özetle, gelen requestleri veritabanına kaydettikten sonra, mesajı kuyruğa publish yapabiliriz. Kuyruk ile mesajları işledikten sonra veritabanında ilgili mesajın durumunu güncelleyebiliriz.

Böylece servise gelen requestlerin kuyrukta işlendiğinden emin olabiliriz. Yanı sıra kuyruklarımızın izlenebilirliğini de arttırmış oluruz.

Inbox Flow Chart
  1. Gelen requesti validate ettikten sonra veritabanına kaydediyoruz.
  2. İşlem başarılı ise kuyruğa bir mesaj bırakıp response dönüyoruz.
  3. Kuyruktaki akış Outbox ile benzerlik gösteriyor. Farklı olan kısım bu sefer transaction açıp gerekli işlemleri yapıyoruz.
  4. Transaction sonucuna göre işlem başarılı sonlanır yada tekrar denenir.
  5. Her istek kuyrukta 3 kere deneniyor. Hepsi başarısız olursa kuyruktan siliniyor.

Tablo Yapısı

Son olarak örnek olması için bütün requestleri sakladığımız tablo ve alanlarından bahsetmek istiyor

    public class TableName : EntityBase
{
[Key]
public Guid EventId { get; set; }
[Required]
public string Type { get; set; }
[Required]
public string Data { get; set; }
[Required]
public string DataType { get; set; }
[Required]
public string KeyData { get; set; }
[Required]
public string State { get; set; }
[Required]
public string MessageBus { get; set; }
[Required]
public string Topic { get; set; }
[Required]
public string Group { get; set; }
[Required]
public byte TryCount { get; set; }
public string Desc { get; set; }
}

Bu alanların kullanım amaçlarını şöyle açıklayabilirim.

  • EventId : Tablonun primary key alanıdır. Aynı zamanda kuyruklara bu veriyi mesaj olarak gönderiyoruz.
  • Type : Inbox/Outbox ayrımını yapmak için kullanıyoruz.
  • Data : Saklanılmak istenilen requestin json hali.
  • DataType : Json verinin tipi.
  • State : Kaydın son durumunu takip için kullanıyoruz.
  • MessageBus : Kuyruğun olduğu MessageBus’ı belirtir.
  • Topic : Bu eventin hangi kuyruğa ait olduğunu belirtir.
  • Group : Kayıtların kendi yapımızda hangi gruba dahil olduğunu saklıyoruz.
  • TryCount : Kaç sefer deneme yapıldığını saklıyoruz. Belli bir değer ulaşanların State değerini güncelleyerek kuyruğu meşgul etmemesini sağlıyoruz.

Bu alanların yanı sıra CreatedDate,Creator, ModifiedDate, Modifier gibi alanlar da mevcut.

Okuduğunuz için teşekkürler. Umarım sizin için faydalı bir yazı olmuştur.

--

--