Resiliência em Aplicações Asp.Net
Por Jonathan Amaral
Nos dias de hoje, garantir a resiliência das nossas aplicações é essencial. Em um mundo onde os sistemas precisam estar disponíveis 100% do tempo, é necessário adotar práticas que permitam que nossos serviços recuperem-se rapidamente de falhas e continuem operando. Neste post, exploraremos as políticas de resiliência em aplicações .NET, utilizando a biblioteca Polly para implementar estratégias eficazes.
O que é Resiliência?
Resiliência é a capacidade de um sistema retornar ao seu estado normal após sofrer algum colapso ou interrupção. Isso é crucial para evitar a perda de produtividade e, por consequência, de receita para o negócio. Partimos da premissa de que tudo pode falhar e, por isso, é preciso preparar nossas aplicações para lidar com esses desafios.
Introduzindo Polly
Polly é uma biblioteca popular para tratamento de falhas transitórias e resiliência em .NET. Ela fornece uma estrutura flexível para definir políticas como tentativas de repetição, timeouts, fallback e circuit breakers. Vamos explorar cada uma dessas políticas e ver exemplos práticos de implementação.
Retry (Repetição)
A política de Retry (ou Retentativa) permite que a aplicação tente repetir uma operação falha, reduzindo a probabilidade de erro ao tentar novamente.
Exemplo de implementação:
Policy.Handle<YourException>()
.WaitAndRetryAsync(
retryCount: 3,
sleepDurationProvider: retryAttempt =>
TimeSpan.FromMilliseconds(settings.RetryInterval * Math.Pow(2, retryAttempt)),
onRetry: (httpResponse, timeSpan, count, context) =>
{
RetryLogRequest(timeSpan, count);
});
- RetryCount: número de tentativas de repetição.
- SleepDurationProvider: define o tempo de espera antes de cada nova tentativa.
- OnRetry: ação chamada a cada nova tentativa, permitindo o log ou manipulação adicional.
Timeout (Tempo Limite)
O Timeout define um tempo máximo de espera para uma operação, ajudando a evitar que chamadas fiquem "presas" indefinidamente.
Exemplo de implementação:
Policy.TimeoutAsync<HttpResponseMessage>(
timeout: TimeSpan.FromMilliseconds(settings.TimeoutInMilliseconds),
timeoutStrategy: TimeoutStrategy.Optimistic,
onTimeoutAsync: (context, timespan, _, exc) =>
{
TimeoutLogRequest(timespan);
return Task.CompletedTask;
});
- Timeout: tempo limite para a operação.
- TimeoutStrategy: define a estratégia, podendo ser "Optimistic" (cancelamento via
CancellationToken) ou "Pessimistic" (bloqueia até o término ou timeout). - OnTimeoutAsync: ação chamada em caso de timeout.
Fallback (Alternativa)
O Fallback fornece uma resposta alternativa para operações que falhem, garantindo que o sistema continue funcionando.
Exemplo de implementação:
using var defaultFallBack = new HttpResponseMessage(HttpStatusCode.FailedDependency);
defaultFallBack.RequestMessage = new HttpRequestMessage();
Policy<HttpResponseMessage>
.Handle<HttpRequestException>()
.OrResult(result => result.StatusCode == HttpStatusCode.ServiceUnavailable)
.FallbackAsync(fallbackValue: defaultFallBack, onFallbackAsync: (http, context) =>
{
FallbackLogRequest(http.Result.StatusCode, defaultFallBack.StatusCode);
return Task.CompletedTask;
});
- FallbackValue: valor substituto a ser usado em caso de falha.
- OnFallbackAsync: ação executada antes de retornar o valor alternativo.
Circuit Breaker (Disjuntor)
O Circuit Breaker impede tentativas contínuas quando um serviço está com problemas, interrompendo as operações por um tempo para evitar sobrecarga.
Exemplo de implementação:
HttpPolicyExtensions
.HandleTransientHttpError()
.AdvancedCircuitBreakerAsync(
failureThreshold: 0.25,
samplingDuration: TimeSpan.FromSeconds(60),
minimumThroughput: 7,
durationOfBreak: TimeSpan.FromSeconds(30),
onBreak: (ex, timeSpan) => CircuitBreakerLogRequest(CircuitState.Open),
onReset: () => CircuitBreakerLogRequest(CircuitState.Closed),
onHalfOpen: () => CircuitBreakerLogRequest(CircuitState.HalfOpen));
- FailureThreshold: limite de falha para interromper o circuito.
- SamplingDuration: janela de tempo para medir a taxa de falhas.
- MinimumThroughput: mínimo de requisições para que o disjuntor entre em ação.
- DurationOfBreak: tempo que o circuito permanecerá aberto.
Demonstração Prática
Para ver essas implementações em ação, acesse o repositório StoneBreakeven no GitHub, onde apresento exemplos práticos dessas políticas.
Essas práticas são essenciais para garantir que suas aplicações ASP.NET sejam resilientes, mantendo a continuidade dos serviços mesmo diante de falhas inesperadas.
Comentários
Postar um comentário