Desenvolvimento

17 abr, 2019

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

100 visualizações
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á!