Desenvolvimento

17 abr, 2019

Criando aplicações resilientes com o padrão Retry

Publicidade

No artigo anterior vimos que algumas das falhas possíveis em nossa aplicação são as falhas transientes. Essas falhas são automaticamente corrigidas após um curto período de tempo.

O padrão (ou política) Retry torna nossa aplicação resiliente ao fazer novas tentativas (automaticamente, em caso de falha).

A animação abaixo mostra o princípio de funcionamento do Retry. Neste cenário configuramos o mecanismo para fazer até cinco novas tentativas em caso de falha (se você preferir um GIF, clique aqui):

Um ponto importante neste exemplo é que, ao tornar nossa aplicação resiliente, o usuário final talvez não tenha percebido que houve falhas nas tentativas de comunicação. Ele fez uma requisição e teve seu resultado. Com isso, podemos dizer que melhoramos a experiência do usuário.

Algumas outras configurações possíveis deste padrão, são:

  • RetryForever: fazer tentativas (eternamente) até que se tenha sucesso
  • Retry(N): fazer N tentativas, e só após as N tentativas a falha é apresentada
  • WaitAndRetry(N, T): fará até no máximo N tentativas e esperará por T tempo entre cada tentativas (essa foi a forma utilizada na animação)

Retry Exponencial (Backoff)

Na configuração de Wait and Retry, uma das formas usuais de configurar os intervalos entre tentativas é o chamado Retry Exponencial, na qual o intervalo cresce de forma exponencial.

Se você é usuário do Gmail, por exemplo, já deve ter percebido essa situação. Veja na animação (acelerada) abaixo das tentativas de reconexão realizadas pelo Gmail quando ficamos sem conexão com a internet:

Ao plotar os intervalos entre as tentativas, fica claro que se trata de uma distribuição exponencial:

Distribuição Exponencial dos intervalos entre tentativas do Gmail

Implementando o Padrão Retry

Se você é desenvolvedor, já deve estar imaginando como implementar esse padrão usando algumas estruturas como condicionais, laços de repetição e tratamentos de erros.

Não será necessário quebrar muito a cabeça, pois existem frameworks prontos e que facilitarão muito nossa vida. Entre eles está o Polly Framework para aplicações .NET.

Polly é uma biblioteca que implementa uma gama de padrões de resiliência e tolerância a falhas para .Net e faz parte da .Net Foundation.

Outras features importantes dessa biblioteca é a linguagem fluente de escrita de padrões de resiliência através de políticas, facilitar a reusabilidade, tratamentos nativos para Thread Safe e suporte Async. Muito Bom!

Implementando Retry com Polly

Veja como é simples:

// Retry a specified number of times, using a function to 
// calculate the duration to wait between retries based on 
// the current retry attempt (allows for exponential backoff)
// In this case will wait for
//  2 ^ 1 = 2 seconds then
//  2 ^ 2 = 4 seconds then
//  2 ^ 3 = 8 seconds then
//  2 ^ 4 = 16 seconds then
//  2 ^ 5 = 32 seconds
Policy
    .Handle<SomeException>()
    .WaitAndRetry(5, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)))
    .Execute(() =>
    {
        // myService.Post(...)...
    });

Analisando:

  • Policy indica que iniciaremos uma nova política de resiliência
  • A função Handle indica que a política só será ativada se ocorrer a exceção SomeException
  • A função WaitAndRetry indica a política que queremos e o argumento 5 indica que fará até cinco tentativas com um intervalo exponencial
  • Colocamos na função Execute o código que será executado pela política, seja ele um procedimento (void) ou função

Observe que a Polly tornou nossa política de retry explícita e legível, sem que precisássemos interpretar os condicionais, laços de repetição, etc.

A biblioteca Polly permite que você crie as políticas de diversas formas e configurações. O código acima é simples e usual para vários cenários.

O site oficial da biblioteca Polly é bem rico em conteúdo e pode ser melhor explorado. Espero que tenham gostado e não se esqueçam de deixar seus feedbacks.

No próximo artigo falaremos sobre o Circuit Breaker.

Até lá!