DevLog #03 – Padrões de Resiliência: Retry, Circuit Breaker e Bulkhead
DevLogDevLog #03 – Padrões de Resiliência: Retry, Circuit Breaker e Bulkhead
📅 Data: 20 de Janeiro de 2026
✍️ Autor: Luís Gabriel Marchió Batista
Por que Resiliência é Crítica
Em uma arquitetura serverless event-driven, falhas são inevitáveis. A chave é recuperar-se rapidamente.
1. Retry com Exponential Backoff
Não tentamos novamente imediatamente. Usamos exponential backoff:
public async Task<T> ExecuteWithRetryAsync<T>(
Func<Task<T>> operation,
int maxAttempts = 3)
{
for (int attempt = 0; attempt < maxAttempts; attempt++)
{
try
{
return await operation();
}
catch (Exception ex) when (attempt < maxAttempts - 1)
{
var delay = TimeSpan.FromMilliseconds(Math.Pow(2, attempt) * 100);
await Task.Delay(delay);
}
}
}
2. Circuit Breaker Pattern
Evitamos cascata de falhas parando de chamar um serviço que está falhando.
var circuitPolicy = Policy
.Handle<HttpRequestException>()
.OrResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
.CircuitBreakerAsync<HttpResponseMessage>(
handledEventsAllowedBeforeBreaking: 5,
durationOfBreak: TimeSpan.FromSeconds(30),
onBreak: (outcome, timespan) =>
{
_logger.LogWarning($"Circuit breaker aberto por {timespan.TotalSeconds}s");
}
);
3. Bulkhead Isolation
Isolamos recursos para que uma falha não afete todo o sistema.
var bulkheadPolicy = Policy.BulkheadAsync(
maxParallelization: 10,
maxQueuingActions: 5,
onBulkheadRejectionAsync: context =>
{
_logger.LogWarning("Bulkhead rejeitou requisição");
return Task.CompletedTask;
}
);
Combinando Padrões
Combinamos esses padrões em uma Polly Policy única:
var policyWrap = Policy.WrapAsync(
retryPolicy,
circuitBreakerPolicy,
bulkheadPolicy
);
Conclusão
Com esses padrões, nosso Order Pipeline pode se recuperar de falhas automaticamente e evitar cascatas de erro.