Partilhar via


Introdução ao desenvolvimento de aplicativos resilientes

A resiliência é a capacidade de uma aplicação se recuperar de falhas transitórias e continuar a funcionar. No contexto da programação .NET, a resiliência é alcançada projetando aplicações que conseguem lidar com falhas de forma elegante e recuperar rapidamente. Para ajudar a construir aplicações resilientes em .NET, os seguintes dois pacotes estão disponíveis no NuGet:

Pacote NuGet Descrição
📦 Microsoft.Extensões.Resiliência Fornece mecanismos para reforçar as aplicações contra falhas transitórias. As versões 10.x.x deste pacote suportam aplicações direcionadas a .NET, .NET Framework e .NET Standard.
📦 Microsoft.Extensões.Http.Resiliência Fornece mecanismos de resiliência especificamente para a classe HttpClient.

Estes dois pacotes NuGet são construídos utilizando o Polly, que é um projeto open-source popular. Polly é uma biblioteca de resiliência e tratamento de falhas transitórias para .NET que permite aos desenvolvedores expressar estratégias como tentativa automática, disjuntor, tempo limite, isolamento de compartimentos, limitação de taxa, alternativa e distribuição de riscos de forma fluente e segura para threads.

Importante

O pacote NuGet Microsoft.Extensions.Http.Polly está obsoleto. Utilize em vez disso qualquer um dos pacotes mencionados anteriormente.

Introdução

Para começar a usar resiliência em .NET, instale a versão mais recente do pacote Microsoft.Extensions.Resilience NuGet.

dotnet add package Microsoft.Extensions.Resilience

Para obter mais informações, consulte dotnet package add ou Manage package dependencies in .NET applications.

Construir uma linha de resiliência

Para utilizar a resiliência, deve primeiro construir um conjunto de estratégias baseadas em resiliência. Cada estratégia configurada é executada na ordem da configuração. Por outras palavras, a ordem é importante. O ponto de entrada é um método de extensão no tipo IServiceCollection, chamado AddResiliencePipeline. Este método recebe um identificador do pipeline e um delegado que configura o pipeline. É passada ao delegado uma instância de ResiliencePipelineBuilder, que é utilizada para adicionar estratégias de resiliência ao pipeline.

Considere o seguinte exemplo baseado em string key.

using Microsoft.Extensions.DependencyInjection;
using Polly;
using Polly.CircuitBreaker;
using Polly.Registry;
using Polly.Retry;
using Polly.Timeout;

var services = new ServiceCollection();

const string key = "Retry-Timeout";

services.AddResiliencePipeline(key, static builder =>
{
    // See: https://www.pollydocs.org/strategies/retry.html
    builder.AddRetry(new RetryStrategyOptions
    {
        ShouldHandle = new PredicateBuilder().Handle<TimeoutRejectedException>()
    });

    // See: https://www.pollydocs.org/strategies/timeout.html
    builder.AddTimeout(TimeSpan.FromSeconds(1.5));
});

O código anterior:

  • Cria uma nova instância ServiceCollection.
  • Define um key para identificar a pipeline.
  • Adiciona um pipeline de resiliência à instância ServiceCollection.
  • Configura o pipeline com estratégias de repetição e tempo limite.

Cada pipeline está configurado para um determinado key, e cada key é usado para identificar o seu correspondente ResiliencePipeline ao obter o pipeline do fornecedor. O key é um parâmetro de tipo genérico do método AddResiliencePipeline.

Extensões do construtor de pipeline de resiliência

Para adicionar uma estratégia ao pipeline, chame qualquer um dos métodos de extensão disponíveis na instância Add*.

  • AddRetry: Tente novamente se algo falhar, o que é útil quando o problema é temporário e pode desaparecer.
  • AddCircuitBreaker: Pare de tentar se algo estiver avariado ou ocupado, o que o beneficia por evitar perder tempo e piorar as coisas.
  • AddTimeout: Desista se algo demorar muito, o que pode melhorar o desempenho ao liberar recursos.
  • AddRateLimiter: Limite o número de pedidos que aceita, o que lhe permite controlar a carga de entrada.
  • AddConcurrencyLimiter: Limite quantos pedidos faz, permitindo-lhe controlar a carga de saída.
  • AddFallback: Faça algo diferente quando enfrentar falhas, o que melhora a experiência do utilizador.
  • AddHedging: Envie múltiplos pedidos em caso de alta latência ou falha, o que pode melhorar a capacidade de resposta.

Para mais informações, consulte Estratégias de Resiliência. Para exemplos, consulte Construir aplicações HTTP resilientes: Padrões-chave de desenvolvimento.

Enriquecimento de métricas

Enriquecimento é a ampliação automática de telemetria com estado bem conhecido, na forma de pares nome/valor. Por exemplo, uma aplicação pode gerar um log que inclua a operação e o código de resultado como colunas para representar o resultado de uma operação. Nesta situação e dependendo do contexto periférico, o enriquecimento adiciona Cluster name, Process name, Region, Tenant ID, e mais ao log à medida que é enviado para o backend de telemetria. Quando o enriquecimento é adicionado, o código da aplicação não precisa fazer nada extra para beneficiar de métricas enriquecidas.

Como o enriquecimento funciona

Imagine 1.000 instâncias de serviço distribuídas globalmente gerando registos e métricas. Quando encontrar um problema no seu painel de serviço, é crucial identificar rapidamente a região ou o centro de dados problemático. O enriquecimento garante que os registos métricos contenham as informações necessárias para identificar falhas em sistemas distribuídos. Sem enriquecimento, o ónus recai sobre o código da aplicação para gerir internamente este estado, integrá-lo no processo de registo e transmiti-lo manualmente. O enriquecimento simplifica este processo, tratando-o sem problemas, sem afetar a lógica da aplicação.

No caso de resiliência, quando adiciona enriquecimento, as seguintes dimensões são adicionadas à telemetria de saída:

  • error.type: Versão de baixa cardinalidade das informações de uma exceção.
  • request.name: O nome do pedido.
  • request.dependency.name: O nome da dependência.

Sob a superfície, o enriquecimento de resiliência é construído sobre a Telemetria do Polly MeteringEnricher. Para mais informações, consulte Polly: Medição de enriquecimento.

Adicionar enriquecimento de resiliência

Além de registar um pipeline de resiliência, pode também registar um enriquecimento de resiliência. Para adicionar enriquecimento, chame o método de extensões em AddResilienceEnricher(IServiceCollection) na instância IServiceCollection.

services.AddResilienceEnricher();

Ao chamar o método de extensão AddResilienceEnricher, está a adicionar dimensões além das que são padrão e que estão integradas na biblioteca Polly subjacente. As seguintes dimensões de enriquecimento são adicionadas:

Utilize pipeline de resiliência

Para utilizar um pipeline de resiliência configurado, deve obter o pipeline a partir de um ResiliencePipelineProvider<TKey>. Quando você adicionou o pipeline anteriormente, o key era do tipo string, portanto, você deve obter o pipeline do ResiliencePipelineProvider<string>.

using ServiceProvider provider = services.BuildServiceProvider();

ResiliencePipelineProvider<string> pipelineProvider =
    provider.GetRequiredService<ResiliencePipelineProvider<string>>();

ResiliencePipeline pipeline = pipelineProvider.GetPipeline(key);

O código anterior:

  • Constrói um ServiceProvider a partir da instância ServiceCollection.
  • Obtém o ResiliencePipelineProvider<string> do prestador de serviços.
  • Recupera ResiliencePipeline de ResiliencePipelineProvider<string>.

Executar o pipeline de resiliência

Para utilizar o pipeline de resiliência, chame qualquer um dos métodos disponíveis na instância. Por exemplo, considere uma chamada de exemplo para o método ExecuteAsync.

await pipeline.ExecuteAsync(static cancellationToken =>
{
    // Code that could potentially fail.

    return ValueTask.CompletedTask;
});

O código anterior executa o delegado dentro do método ExecuteAsync. Quando há falhas, as estratégias configuradas são executadas. Por exemplo, se o RetryStrategy estiver configurado para tentar novamente três vezes, o representante é executado quatro vezes (uma tentativa inicial mais três tentativas de repetição) antes que a falha seja propagada.

Consulte também