System Design/05 - Reliability Patterns/Resiliency2 min
Retry
- Que problema isso resolve?
- Quando usar / quando NÃO usar?
- Qual o principal trade-off?
- Como isso falha em produção?
Conceito
Repetir uma operação que falhou, apostando que a falha era transitória.
Quando repetir — e quando não
| Repetir | Não repetir |
|---|---|
| Timeout de rede | 400 Bad Request |
503 Service Unavailable |
401 / 403 |
429 Too Many Requests (com Retry-After) |
404 Not Found |
| Deadlock ou lock timeout | 422 — dado inválido |
| Falha de conexão | Erro de lógica |
A regra: repetir 4xx (exceto 429) não adianta — o pedido está errado e continuará errado.
Backoff exponencial com jitter
for tentativa in range(3):
try: return operacao()
except TransitorioError:
if tentativa == 2: raise
espera = min(2 ** tentativa, 30) * random.uniform(0.5, 1.5)
time.sleep(espera)
Jitter é a parte mais importante e a mais esquecida. Backoff sem jitter mantém os clientes sincronizados: todos esperam 1 s, depois 2 s, depois 4 s — juntos. O serviço recebe rajadas periódicas e nunca se recupera entre elas.
Trade-offs
Retry aumenta a chance de sucesso numa falha transitória e piora qualquer falha sistêmica — é a mecânica do Retry Storm. Como distinguir uma da outra em tempo real é difícil, a proteção prática é limitar o dano: teto de tentativas, retry budget (no máximo 10% do tráfego pode ser retry) e Circuit Breaker por cima.
O segundo risco é a multiplicação em cascata: se cada camada repete três vezes, quatro camadas encadeadas produzem 81 requisições para uma chamada original. A prática correta é repetir numa camada só, tipicamente a mais externa, e deixar as internas falharem rápido.
E a condição inegociável: retry só é seguro em operação idempotente. Repetir uma cobrança não idempotente cobra duas vezes — e o cliente não vai aceitar "foi um timeout" como explicação.
Vale lembrar que uma resposta perdida é indistinguível de uma requisição não processada. O cliente que repete não sabe se a primeira funcionou; só a idempotência torna a dúvida irrelevante (Idempotent Operations).
Exemplo prático
Uma chamada a um gateway de pagamento que sofre timeout.
Sem chave de idempotência, repetir é apostar: se a primeira tentativa chegou e só a resposta se perdeu, o cliente é cobrado duas vezes.
Com chave de idempotência, o retry é seguro:
POST /cobranca
Idempotency-Key: 7f3a-...
A segunda tentativa com a mesma chave devolve a resposta da primeira, sem cobrar de novo. É essa combinação — retry com backoff e jitter, sobre operação idempotente, com circuit breaker por cima — que torna a resiliência segura em vez de perigosa.
Relacionado
Parte de Resiliency · roadmap.sh/system-design