Gå til indholdet

Introduktion til Polly

Polly er et populært .NET-baseret open source-bibliotek, der hjælper med at implementere fejltolerance og fejlhåndtering i applikationer ved hjælp af foruddefinerede politikker. Det er særligt nyttigt i distribuerede systemer, hvor netværksfejl og forsinkelser kan påvirke applikationens ydeevne og stabilitet. Polly understøtter en række politikker, herunder Retry, Circuit Breaker, Timeout, Bulkhead Isolation og Cache.

Se Polly på GitHub og Polly NuGet-pakken for yderligere oplysninger.

Retry politik

Retry politikken er en af de mest grundlæggende politikker i Polly. Den bruges til at gøre et nyt forsøg på at udføre en handling, hvis den fejler. Dette kan være nyttigt i situationer, hvor en fejl kan skyldes midlertidige problemer, såsom netværksforstyrrelser eller overbelastede servere.

using Polly;
using Polly.Retry;

var retryPolicy = Policy
    .Handle<HttpRequestException>()
    .RetryAsync(3);

Anvend politikken ved at indpakke koden, der skal udføres, med ExecuteAsync-metoden:

await retryPolicy.ExecuteAsync(async () =>
{
    // Kode, der skal udføres med Retry politik
});

Circuit Breaker politik

Circuit Breaker politikken er designet til at forhindre, at en applikation fortsætter med at foretage anmodninger, når en tjeneste er nede eller fungerer dårligt. Når en bestemt fejlgrænse nås, “bryder” politikken kredsløbet og blokerer yderligere anmodninger i en bestemt periode.

using Polly;
using Polly.CircuitBreaker;

var circuitBreakerPolicy = Policy
    .Handle<HttpRequestException>()
    .CircuitBreakerAsync(
        exceptionsAllowedBeforeBreaking: 3,
        durationOfBreak: TimeSpan.FromSeconds(30));

Anvend politikken ved at indpakke koden, der skal udføres, med ExecuteAsync-metoden:

await circuitBreakerPolicy.ExecuteAsync(async () =>
{
    // Kode, der skal udføres med Circuit Breaker politik
});

Timeout politik

Timeout politikken bruges til at begrænse den tid, en handling er tilladt at tage, før den betragtes som mislykket. Dette kan være nyttigt for at forhindre, at en applikation bliver blokeret, når en ekstern tjeneste tager for lang tid at svare.

using Polly;
using Polly.Timeout;

var timeoutPolicy = Policy
.TimeoutAsync(3); // Angiver en timeout på 3 sekunder

Anvend Timeout politikken på en handling:

await timeoutPolicy.ExecuteAsync(async () => await SlowOperationAsync());

Større eksempel

Se eksempelvis dette eksempel (inspireret/klippet fra en glimrende artikel: Retry Pattern using Polly in C#), hvor der hentes data fra HttpBin over nettet via HttpClient. Deres services kan bruges til at teste http kald, og dette kald returnerer enten en status kode 200 eller en status kode 408 (RequestTimeout).

I koden foretages kald og status koden udskrives - ligegyldigt om det er 200 eller 408.

using System;
using System.Net.Http;
using System.Threading.Tasks;

namespace ConsoleApp3
{
    class Program
    {
        static async Task Main(string[] args)
        {
            var httpClient = new HttpClient();
            var response = await httpClient.PostAsync("https://httpbin.org/status/200,408", null);
            if (response.IsSuccessStatusCode)
                Console.WriteLine("Status 200");
            else
                Console.WriteLine("Status 408");
        }
    }
}

Her er samme kode men nu pakket ind i Polly, som sørger for at gentage kald tre gange med et sekunds interval indtil en eventuel status 200.

using System;
using System.Net.Http;
using System.Threading.Tasks;
using Polly;

namespace RetryPattern
{
    class Program
    {
        static async Task Main(string[] args)
        {
            var httpClient = new HttpClient();
            var response = await Policy
                            .HandleResult<HttpResponseMessage>(message => !message.IsSuccessStatusCode)
                            .WaitAndRetryAsync(new[]
                            {
                                TimeSpan.FromSeconds(1),
                                TimeSpan.FromSeconds(1),
                                TimeSpan.FromSeconds(1)
                            }, (result, timeSpan, retryCount, context) => {
                                Console.WriteLine($"Request failed with {result.Result.StatusCode}. Retry count = {retryCount}. Waiting {timeSpan} before next retry. ");
                            })
                            .ExecuteAsync(() => httpClient.PostAsync("https://httpbin.org/status/200,408", null));

            if (response.IsSuccessStatusCode)
                Console.WriteLine("Status 200");
            else
                Console.WriteLine("Status 408");
        }
    }
}