Resiliência não é esconder falhas
Imagine que o serviço de catálogo responda em dois segundos, mas o checkout espere no máximo meio segundo. Sem limite, cada requisição lenta continua ocupando recursos. Quando o tráfego aumenta, chamadas acumuladas podem esgotar o serviço chamador também. Uma aplicação resiliente conhece seus limites, falha de forma explícita e preserva as funções mais importantes.
Comece pelo comportamento do produto: quanto tempo o usuário pode esperar? A operação pode ser repetida sem duplicar efeitos? Existe uma resposta degradada segura? Essas respostas definem políticas; não há um número universal de tentativas ou timeout apropriado a todos os serviços.
Timeout: toda espera precisa de um limite
Configure timeouts em chamadas de rede e alinhe-os ao orçamento total da requisição. Se o endpoint tem um segundo para responder, não faz sentido permitir que uma dependência individual aguarde dez segundos. Propague cancelamento para que trabalho que já não interessa deixe de consumir recursos.
Timeout não prova que o servidor remoto não executou a operação: a resposta pode ter se perdido depois da gravação. Para operações com efeito, combine a política com chave de idempotência e verificação de estado.
Retries com critério, backoff e jitter
Uma repetição pode recuperar uma falha transitória, como uma conexão interrompida. Mas repetir imediatamente em todos os clientes amplifica o tráfego justamente quando a dependência está sobrecarregada. Use poucas tentativas, atraso crescente (backoff), variação aleatória (jitter) e um prazo total. Não repita erros permanentes nem operações não idempotentes sem proteção.
// Exemplo conceitual: a biblioteca deve limitar tentativas e respeitar o prazo.
var atraso = TimeSpan.FromMilliseconds(200);
for (var tentativa = 1; tentativa <= 3; tentativa++)
{
try { return await consultar(cancellationToken); }
catch (HttpRequestException) when (tentativa < 3)
{
await Task.Delay(adicionarJitter(atraso), cancellationToken);
atraso = TimeSpan.FromMilliseconds(atraso.TotalMilliseconds * 2);
}
}
throw new InvalidOperationException("A consulta não foi concluída.");Prefira políticas conhecidas da plataforma a código de retry improvisado. Evite retries em camadas diferentes sem coordenar limites: três tentativas em cada uma de três camadas podem produzir até 27 chamadas.
Circuit breaker e bulkhead
Um circuit breaker interrompe temporariamente chamadas quando uma dependência falha repetidamente. No estado aberto, a aplicação falha rápido; depois de uma pausa, permite algumas chamadas de teste antes de fechar o circuito. Isso reduz pressão e dá tempo para recuperação. Circuit breaker não corrige a dependência nem substitui timeout.
Bulkhead limita concorrência ou recursos por dependência, como compartimentos de um navio: uma integração saturada não consome toda a capacidade do processo. Fallback só é correto quando o resultado alternativo é seguro e compreensível; retornar dados antigos ou sucesso fictício pode ser pior que informar indisponibilidade.
Mensagens, idempotência e recuperação
Em mensageria, atraso e repetição fazem parte do modelo. Consumidores devem reconhecer duplicatas ou tornar o efeito idempotente; mensagens que falham repetidamente precisam de política de retry e destino de quarentena, com processo para investigar e reprocessar. Filas não eliminam falhas: tornam o trabalho assíncrono e desacoplam ritmos.
Para coordenar etapas de negócio e publicação confiável, veja Saga, Outbox e Inbox. A estratégia de broker também importa: compare Kafka, RabbitMQ e Azure Service Bus.
Como saber se está funcionando?
Defina objetivos de disponibilidade e latência, acompanhe taxa de erro, duração e saturação, e correlacione falhas com dependências. Instrumente os estados das políticas: circuitos abertos, tentativas, timeouts e mensagens em dead-letter. A página de observabilidade explica como transformar esses sinais em diagnóstico, não em ruído.
Resiliência precisa ser exercitada com cenários controlados: dependência lenta, indisponível, respostas inválidas e recuperação. A meta não é provar que nada falha; é confirmar que falhas não se propagam sem controle e que a equipe consegue restaurar o serviço.