Implementar novas tentativas de chamada HTTP com backoff exponencial com políticas IHttpClientFactory e Polly

Gorjeta

Este conteúdo é um trecho do eBook, .NET Microservices Architecture for Containerized .NET Applications, disponível no .NET Docs ou como um PDF para download gratuito que pode ser lido offline.

.NET Microservices Architecture for Containerized .NET Applications eBook cover thumbnail.

A abordagem recomendada para novas tentativas com backoff exponencial é aproveitar bibliotecas .NET mais avançadas, como a biblioteca Polly de código aberto.

Polly é uma biblioteca .NET que fornece resiliência e recursos de tratamento de falhas transitórias. Você pode implementar esses recursos aplicando políticas Polly, como Retry, Circuit Breaker, Bulkhead Isolation, Timeout e Fallback. Polly tem como alvo o .NET Framework 4.x e o .NET Standard 1.0, 1.1 e 2.0 (que oferece suporte ao .NET Core e posterior).

As etapas a seguir mostram como você pode usar novas tentativas de Http com Polly integrado ao IHttpClientFactory, que é explicado na seção anterior.

Instalar pacotes .NET

Primeiro, você precisará instalar o Microsoft.Extensions.Http.Polly pacote.

Fazer referência aos pacotes do .NET 8

IHttpClientFactory está disponível desde o .NET Core 2.1, no entanto, recomendamos que você use os pacotes .NET 8 mais recentes do NuGet em seu projeto. Normalmente, você também precisa fazer referência ao pacote Microsoft.Extensions.Http.Pollyde extensão.

Configurar um cliente com a política de repetição do Polly, na inicialização do aplicativo

O método AddPolicyHandler() é o que adiciona políticas aos HttpClient objetos que você usará. Neste caso, ele está adicionando uma política do Polly para Http Retries com backoff exponencial.

Para ter uma abordagem mais modular, a Política de Repetição Http pode ser definida em um método separado dentro do arquivo Program.cs , conforme mostrado no código a seguir:

static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
    return HttpPolicyExtensions
        .HandleTransientHttpError()
        .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
        .WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2,
                                                                    retryAttempt)));
}

Como mostrado nas seções anteriores, você precisa definir uma configuração HttpClient de cliente nomeada ou digitada em sua configuração padrão de aplicativo Program.cs . Agora você adiciona código incremental especificando a política para as novas tentativas de Http com backoff exponencial, da seguinte maneira:

// Program.cs
builder.Services.AddHttpClient<IBasketService, BasketService>()
        .SetHandlerLifetime(TimeSpan.FromMinutes(5))  //Set lifetime to five minutes
        .AddPolicyHandler(GetRetryPolicy());

Com o Polly, você pode definir uma política de repetição com o número de tentativas, a configuração de backoff exponencial e as ações a serem tomadas quando houver uma exceção HTTP, como registrar o erro. Nesse caso, a política é configurada para tentar seis vezes com uma repetição exponencial, começando em dois segundos.

Adicionar uma estratégia de desvio à política de repetição

Uma política de repetição regular pode afetar seu sistema em casos de alta simultaneidade e escalabilidade e sob alta contenção. Para superar picos de tentativas semelhantes provenientes de muitos clientes em interrupções parciais, uma boa solução é adicionar uma estratégia de desvio ao algoritmo/política de repetição. Essa estratégia pode melhorar o desempenho geral do sistema de ponta a ponta. Como recomendado em Polly: Retry with Jitter, uma boa estratégia de jitter pode ser implementada por intervalos de repetição suaves e uniformemente distribuídos aplicados com um atraso de repetição inicial mediano bem controlado em um backoff exponencial. Essa abordagem ajuda a espalhar os picos quando o problema surge. O princípio é ilustrado pelo seguinte exemplo:


var delay = Backoff.DecorrelatedJitterBackoffV2(medianFirstRetryDelay: TimeSpan.FromSeconds(1), retryCount: 5);

var retryPolicy = Policy
    .Handle<FooException>()
    .WaitAndRetryAsync(delay);

Recursos adicionais