Polly kütüphanesi Retry Policy kullanımı

Tajdin Arat
inventiv
Published in
4 min readSep 29, 2023

Bu makalede basit bir program ile polly kütüphanesinin retry politikasının kullanımını inceleyeceğiz. İyi okumalar…

Polly Kütüphanesi

Polly geçici hata işleme ve esneklik yetenekleri sunan bir . NET kütüphanesidir. Polly ile Retry, Circuit Breaker, BulkHead Isolation, Timeout ve Fallback gibi ilkeleri uygulayabilirsiniz.

Biz bu makalemizde Retry ilkesini basit bir .NET uygulaması üzerinde genel implementasyonunu göstermeye çalıştık. Keyifli okumalar dileriz.

Retry Policy Nedir?

Retry politikası başarısız bir işlemi şeffaf bir şekilde nasıl yeniden deneneceğini, bir uygulamanın bir hizmete veya ağ kaynağına bağlanmaya çalıştığında geçici hataları nasıl ele alacağını bildiren bir öznitelikler koleksiyonudur.

Retry Pattern çalışma mekanizması

Şimdi implementasyon örneği ile bu konuyu somutlaştıralım.

İmplementasyon

Yeni bir web uygulaması oluşturun. İlk uygulama bizim ‘Main’ uygulamamız olacak. Bu uygulamanın içinde önce politikaları belirleyeceğimiz bir sınıf açalım.

PolicyBuilder.cs

using Polly;
using Polly.Extensions.Http;
using System.Net;

namespace MainProject
{
public class PolicyBuilder
{
public IAsyncPolicy<HttpResponseMessage> GetRetryPolicy(HttpStatusCode[] httpStatusCodes)

{
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(r => httpStatusCodes.Contains(r.StatusCode))
.WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(3, retryAttempt)),
(exception, timespan, retryAttempt, context) =>
{
Console.WriteLine($"Retry #{retryAttempt} due to {exception.Exception.Message}. Waiting for {timespan.TotalSeconds} seconds.");
});
}
}
}

Burada belirtilen politika Retry mekanizmasının oluşturulmasında kullanılacaktır. Burada handle edilecek hata kodları ve yeniden denemede alınacak aksiyonlar belirlenmiştir.

HandleTransientHttpError metodu Http 408 ve 5XX kodlarını handle eder.

OrResult metodunda bu kodlara ek olarak handle edilmek istenen hata kodları eklenebilir. (Bu kodlar birazdan alıntılayacağımız Program.cs sınıfında tanımlanmıştır.)

WaitAndRetryAsync metodu yeniden deneme yapılırken hangi işlemlerin yapılacağının tanımlandığı metoddur. Üç parametre alır.

Parametrelerden ilki ‘RetryCount’ parametresidir, bu parametre hata alınan servise toplamda kaç kere yeniden deneme yapılacağını belirtir.
İkinci parametre ‘RetryAttempt’ adlı, action alan bir parametredir. Bu parametre sleep duration (bekleme zaman aralığı) bilgisini sağlar.
Üçüncü parametre ise ‘OnRetry’ parametresidir. Bu parametre bir delegate alır. Bu delegate exception ve retryCount parametrelerini alır.

Program.cs

using MainProject;
using Polly;
using System.Net;

internal class Program
{
private static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);

var policyBuilder = new MainProject.PolicyBuilder();

HttpStatusCode[] httpStatusCodesWorthRetrying = {
HttpStatusCode.RequestTimeout, // 408
HttpStatusCode.InternalServerError, // 500
HttpStatusCode.BadGateway, // 502
HttpStatusCode.ServiceUnavailable, // 503
HttpStatusCode.GatewayTimeout // 504
};

var retryPolicy = policyBuilder.GetRetryPolicy(httpStatusCodesWorthRetrying);

builder.Services.AddControllers();

builder.Services.AddHttpClient("providerApiClient", c =>
{
c.BaseAddress = new Uri("https://localhost:7099");
}).AddTransientHttpErrorPolicy(p => retryPolicy);

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();
}
}

Burada açtığımız web uygulamasının ana sınıfı olan Program.cs içinde öncelikle PolicyBuilder sınıfımızdan bir policyBuilder yarattık. Daha sonra bu nesne ile GetRetryPolicy metoduna, mekanizma tarafından handle edilen 408 ve 5XX kodları haricinde handle edilmesini istediğimiz Http kodlarını pasladık.

Daha sonra bu politikayı ilgili Http client’a AddTransientHttpErrorPolicy metodu ile ekledik. En son endpointleri ve swagger’ı ekledik ve uygulamamız çalışabilir hâle geldi.

Burada belirtilen “https://localhost:7099” adresi başka bir uygulama bağlı olmadığından “500 Internal Server Error” hata kodu atacaktır. Bu da uygulamanın yeniden deneme mekanizmasını devreye alacaktır.

Aşağıdaki görselde belirli sürelerde deneme yapılıp hata döndüğünü ve üçüncü denemede isteğin başarılı olduğunu görebiliyoruz.

Uygulamanın örnek konsol çıktısı

Burada daha önce bahsettiğimiz gibi “https://localhost:7099” adresine bağlı başka bir uygulamayı ilk iki deneme zaman zarfında kapalı tutup daha sonra üçüncü denemeden hemen önce çalıştırdığımız için, ilk iki denemede 500, üçüncü denemede ise Success mesajı aldık.

Ne Zaman Retry Pattern Kullanmalıyız?

  1. Geçici (transient/temporary) hatalar :
    Bu hatalar genelde connection timeout veya benzeri hatalardır. Bu tür hatalarda genelde belli bir süre geçtikten sonra tekrar denemek sistemden yanıt alabilmenize olanak sağlayacaktır.
    Unutmayın! Bad Request hataları geçici değildir ve bu hatayı aldığınızda yeniden denemek pek de mantıklı değildir. Bu hatalar gönderdiğiniz istekte bir problem olduğunu veya server’ın bu isteği işleyemeyecek olduğunu belirtir.
  2. Sistem hataları :
    Sistem hataları genelde yeniden deneme yapmak için uygundur. Bu hatalar isteğin işlenmediğini belirtir. Örneğin timeout aldığınızda istek gitmiş fakat belli bir zaman zarfında işlenememiştir. Timeout retry pattern kullanmak için uygun bir case’dir.
    Fakat… Uygulama hataları gönderdiğiniz istekte bir sorun olduğunu belirtir. Bu sorunlu istekleri ne kadar yeniden denerseniz aynı hata ile karşılaşırsınız. Bu yüzden bu hataları yeniden denemek mantıklı değildir.
  3. Idempotency :
    Idempotent istekler ilk istek yapıldığında da birkaç deneme yapıldığında da aynı sonucu üretecek olan isteklerdir. Bu tarz idempotent API’lar genelde gelen tekrarlı isteklerin ilkini işlemeye devam eder. GET, DELETE ve PUT istekleri idempotent olan, POST isteği idempotent olmayan isteklerdir. Aynı isteğin tipini değiştirerek bundan kaçınmak yerine isteklere requestId gömülebilir. Bu sayede isteği işleyecek olan taraf istek tipine değil de, isteğin id’sine bakacak ve aynı istek farklı request id değerleriyle gönderildiği için farklı değerlendirilecektir.
  4. Yeniden deneme maliyeti :
    Yüksek trafik olan servislerde sürekli yeniden denemenin maliyeti pahalı olacaktır. Bu maliyeti düşürmek adına Retry Pattern kullanılarak hem uygulamaya yeniden deneme işlevi kazandırılabilir hem de yeniden denemeler arasına zaman koyularak, server taraflı kaynak kullanımından tasarruf edilebilir.
  5. Implementasyon maliyeti :
    Bu pattern birçok programlama dilinde kütüphaneler aracılığıyla sunulduğu için uygulamanıza implemente etmeniz kolay olacaktır.

Bitirirken…

Bu yazımızda Polly kütüphanesini kullanarak Retry Pattern örneği verdik. Umarız keyifli bir okuma olmuştur. Uygulamanın kaynak koduna buradan ulaşabilirsiniz. Teşekkürler…

Bu makalenin hazırlanmasındaki katkılarından dolayı Asrin Ziya Hocaoglu’na teşekkürlerimi sunarım.

--

--