Erhan Ballıeker

Resilient Network Services Bölüm 6 – Polly – 2 (Fault-Response-Handling, Wait, Wait And Retry, Forever Retry Policies)

Selamlar,

Bir önceki yazımda Resilient network services sistemi kurgularken ihtiyacımız olacak belki de en önemli kütüphane olan Polly e teorik olarak bir giriş yapmıştık. Okmadıysanız önce buradan başlamnızı öneririm. Bu yazımızda Polly nin başlıktaki konularını detaylı inceleyip kullanımlarına bakacağız.

Öncelikle Polly tarafında Fault handling kısmına bir bakalım.

Polly Policy si tarafından yakalanmasını istediğiniz hataları tanımlamak

// tek bir hata tipi. Bir HttpREquest exception olduğundan policy nin yakalamasını istiyoruz 
//bu hatayı.
Policy
  .Handle<HttpRequestException>()

// Spesifik bir hata numarasına göre tek bir hata tipi.
// SqlException lardan sadece 1205 spesific koduna sahip yani sadece Deadlock hatalarını
// yakalamak istediğimizi söylüyoruz.
Policy
  .Handle<SqlException>(ex => ex.Number == 1205)

// Birden çok yakalamak istediğimiz exception tipi olduğunda kullanacağımız yöntem

Policy
  .Handle<HttpRequestException>()
  .Or<OperationCanceledException>()

// Yine birden çok hata tipi için ama her bir hatanın da belli spesifik 
// kodlu olanlarını yakalamak istediğimiz zaman kullanacağımız yöntem.
Policy
  .Handle<SqlException>(ex => ex.Number == 1205)
  .Or<ArgumentException>(ex => ex.ParamName == "example")

// Sıradan hataların yada daha çok async-await kullanırken alacağımız Aggregate Exception lar
//hem top level hemde inner exceptionlarını yakalayabileceğimiz durum. Istersek OperationCanceledException
// da dediğimiz gibi, belli bir condition verebiliriz.
Policy
  .HandleInner<HttpRequestException>()
  .OrInner<OperationCanceledException>(ex => ex.CancellationToken != myToken)

Request in sonucunda yakalamak istediğimiz Result tiplerine göre Policy ler ayarlamak istediğimiz yöntem

 

// bir Condition belirterek result ı handle etmek istediğimiz durum. 

Policy
  .HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.NotFound)

// birden çok result tipini handle etmek istediğimiz durum.

Policy
  .HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.InternalServerError)
  .OrResult(r => r.StatusCode == HttpStatusCode.BadGateway)

// Sadece belli bir response StatusCode lara göre result ı handle etmek istediğimiz durum

Policy
  .HandleResult<HttpStatusCode>(HttpStatusCode.InternalServerError)
  .OrResult(HttpStatusCode.BadGateway)
 
// Hem hataları hem de responselaru birlikte yakalamak ve handle etmek
//istediğimiz durum. İstediğimiz status codeları bir array de toplayıp,
//hem exceptionları, hem de bu response statüsüne sahip responları handle edip,
// otomatik bir şekilde Retry mekanizmasını çalıştırdığımız durum. 

HttpStatusCode[] httpStatusCodesWorthRetrying = {
   HttpStatusCode.RequestTimeout, // 408
   HttpStatusCode.InternalServerError, // 500
   HttpStatusCode.BadGateway, // 502
   HttpStatusCode.ServiceUnavailable, // 503
   HttpStatusCode.GatewayTimeout // 504
}; 
HttpResponseMessage result = await Policy
  .Handle<HttpRequestException>()
  .OrResult<HttpResponseMessage>(r => httpStatusCodesWorthRetrying.Contains(r.StatusCode))
  .RetryAsync(...)
  .ExecuteAsync( /* some Func<Task<HttpResponseMessage>> */ )

 

Özellikle son örneğe dikkat etmenizi istiyorum. Bu örnek ile Polly nin gücünü ve bize sağladığı faydaları artık anlamaya başlayabiliriz. Uygulamamızın atacağı bi request için,

  • hata aldığında neler olacağını
  • bazı belirlediğimiz status code la dönen responselar için neler olacağını
  • bu gibi durumlar gerçekleştiğinde tekrar request göndermek istediğimizi
  • ve tüm bu işlemlerden biri olduğunda sonuç olarak ne yapmak istediğimizi yazdığımız func ile, ne kadar fazla senaryoyu 5 satır kod ile Polly e söyleyebiliyoruz.

Api ın kullanım şekli Fluent dediğimiz, metodların nokta ile birbiri ardına yazılması şekline kullanılıyor. Bu da yazım esnasında ayrı bir kolaylık sağlıyor.

Policy nin handle ettiği durumlarda neler yapmasını istediğimiz söylemek istediğimiz durum

Retry

// Yalnızca bir kere tekrar dene.
Policy
  .Handle<SomeExceptionType>()
  .Retry()

// Birden çok kez tekrar etmesini istediğimiz durum
Policy
  .Handle<SomeExceptionType>()
  .Retry(3)

// Birden çok tekrar istiyoruz, ve her bir tekrar sonrasında farklı
// bir işlem yapmak istediğimiz durum. Örneğin önyüzde basitçe Tekrar Deneniyor(1.., 2...)
// gibi basit bir notification için.
Policy
    .Handle<SomeExceptionType>()
    .Retry(3, onRetry: (exception, retryCount) =>
    {
        // ...
    });

// yukarıdaki kullanıma artık olarak, her bir yeni deneme sonrası çalışmasını
// istediğimiz metodu yazarken bize Exception ve retryCount un yanında bir de
// Execute içerisinde kullanmış olduğumuz context i dönen metodun kullanım şekli.
Policy
    .Handle<SomeExceptionType>()
    .Retry(3, onRetry: (exception, retryCount, context) =>
    {
        // ... 
    });

Retry Forever (until succeeds)

Request ten başarılı sonuç alana kadar retry etmek istediğimiz durum. Sınırlı senaryo olsa da böyle durum ile karşılaştığımızda background da çalışan bir request için başarlı sonuç alıncaya kadar retry edebiliriz.

// Sürekli tekrar et.

Policy
  .Handle<SomeExceptionType>()
  .RetryForever()

// her bir tekrar sonrası alınan hata detayı ile birlikte ne aksiyon
//almak istediğimizi söyleyebildiğimiz yöntem.
Policy
  .Handle<SomeExceptionType>()
  .RetryForever(onRetry: exception =>
  {
        // ...      
  });

// her bir hata sonrası ne aksiyonu almak istediğimizi hem hata hemde execute ettiğimiz
// context ile beraber bize dönen metodun kullanım şekli..
Policy
  .Handle<SomeExceptionType>()
  .RetryForever(onRetry: (exception, context) =>
  {
        // ...     
  });

Wait and retry

Tekrar etmeler arasında belli bir bekleme süresi koymak istediğimiz durumlarda kullanacağımız yöntem.

// Her bir tekrar sonrası hata yakalama işleminden sonra beklenmesini
// istediğimiz süreleri belirtiyoruz.

Policy
  .Handle<SomeExceptionType>()
  .WaitAndRetry(new[]
  {
    TimeSpan.FromSeconds(1),
    TimeSpan.FromSeconds(2),
    TimeSpan.FromSeconds(3)
  });

// her bir tekrar deneme sonrası beklenmesini istediğimiz süreyi,
// aynı zamanda da yine her bir tekrar deneme sonraı yapmak istediğimiz ekstra bir
// işlem varsa kullanabilceğimiz yöntem.

Policy
  .Handle<SomeExceptionType>()
  .WaitAndRetry(new[]
  {
    TimeSpan.FromSeconds(1),
    TimeSpan.FromSeconds(2),
    TimeSpan.FromSeconds(3)
  }, (exception, timeSpan) => {
    // ...
  }); 

// yukarıdakine ek olarak bize ilgili context i ve yine 
// o deneme öncsi bekleme süresini, hatayı verip, ilgili aksiyonu yazmak istediğimiz yöntem.
Policy
  .Handle<SomeExceptionType>()
  .WaitAndRetry(new[]
  {
    TimeSpan.FromSeconds(1),
    TimeSpan.FromSeconds(2),
    TimeSpan.FromSeconds(3)
  }, (exception, timeSpan, context) => {
    // ...
  });

// her bir yeniden deneme sonrası almak istediğimiz aksiyonu yazarken
// bize (exception, timeSpan, retryCount, context) bu 4 bilgiyi de sağlayan yöntem

Policy
  .Handle<SomeExceptionType>()
  .WaitAndRetry(new[]
  {
    TimeSpan.FromSeconds(1),
    TimeSpan.FromSeconds(2),
    TimeSpan.FromSeconds(3)
  }, (exception, timeSpan, retryCount, context) => {
    // ...   
  });

// Her bir bekleme süresini algoritmik bir sürece bağlamak
// istediğimiz zaman kullanacak olduğumuz yöntem.
// Aşağıdaki örnek için
//  2 ^ 1 = 2 sn
//  2 ^ 2 = 4 sn
//  2 ^ 3 = 8 sn
//  2 ^ 4 = 16 sn
//  2 ^ 5 = 32 sn

Policy
  .Handle<SomeExceptionType>()
  .WaitAndRetry(5, retryAttempt => 
	TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)) 
  );

// Hem bekleme süresini dinamik belirleyip, hemde sonrasında 
// yapmak istediklerimiz için bize, timeSpan, exception ve context i dönen metod.
Policy
  .Handle<SomeExceptionType>()
  .WaitAndRetry(
    5, 
    retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), 
    (exception, timeSpan, context) => {
      // ...
    }
  );

// yukarıdakine ek olarak bize birde retryCount u dönen metod.

Policy
  .Handle<SomeExceptionType>()
  .WaitAndRetry(
    5, 
    retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), 
    (exception, timeSpan, retryCount, context) => {
      // ...
    }
  );

 

Wait and retry forever (until succeeds)

İşlem başarılı olana kadar tekrar ederken herbir tekrar öncesi beklemek istediğimiz ve bu tekrarlar arasında farklı işlemler yapmak istediğimiz durum.

// sürekli bekle ve tekrar et

Policy
  .Handle<SomeExceptionType>()
  .WaitAndRetryForever(retryAttempt => 
	TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))
    );

// Sürekli bekle ve tekrar et ve her bir tekrar deneme sonrası yapmak
// istediğimizi söylediğimiz yöntem.
Policy
  .Handle<SomeExceptionType>()
  .WaitAndRetryForever(
    retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),    
    (exception, timespan) =>
    {
        //...      
    });

// Sürekli bekle ve tekrar et ve her bir tekrar deneme sonrası yapmak
// istediğimizi söylediğimiz yöntem.
Policy
  .Handle<SomeExceptionType>()
  .WaitAndRetryForever(
    retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),    
    (exception, timespan, context) =>
    {
        //...       
    });

Yukarıda sadece Polly nin, Fault ve Response Handling ini ve bunları yaparken Retry-Forever-Retry ve Wait-Retry patternlerinin uygulanış şekillerini gördük.

Bunların dışında daha bahsedeğim özellikleri mevuct polly nin. Sadece bu kadar bile bir sonraki projenizde olmazsa olmaz kütüphanelerinizden biri olduğunu düşünmenize yeteceiğini düşünüyorum 🙂

Bir sonraki yazımda görüşmek üzere.

Bir Cevap Yazın

Aşağıya bilgilerinizi girin veya oturum açmak için bir simgeye tıklayın:

WordPress.com Logosu

WordPress.com hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Facebook fotoğrafı

Facebook hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Connecting to %s

%d blogcu bunu beğendi: