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:

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á!