Pular para o conteúdo

apps/resiliency/retry-pattern

104 · Resiliência & Tolerância a Falhas · ≈ 6 min de estudo

Retry Pattern

Tenta de novo uma operação que falhou por causa transitória — serviço reiniciando, 503, timeout, rate limit —, com teto de tentativas e espera crescente com jitter. Só retenta o que pode dar certo na próxima vez, e só retenta escrita quando o destino é idempotente: a mesma chave em toda tentativa garante um único efeito.

passos
6
arquivos
5
testes
0
tecnologias
4
Lógica puraTypeScriptBunElysiaStryker
Baixar cartão

Cenário

O banco envia PIX para liquidação no BACEN. O SPI às vezes responde 503 por segundos, e às vezes liquida mas a resposta se perde na rede. Retentar o 503 resolve; retentar a resposta perdida sem idempotência debitaria duas vezes. Saldo insuficiente (422) é erro de negócio: nenhuma tentativa muda o resultado, e ele não é retentado.

Planta

Sequência
7/7
idempotencyKey gerada antes do loopPOST /settlements (key K)1503 SPI_UNAVAILABLE2espera aleatória entre 0 e 100 msPOST /settlements (key K)3debita e liquida4resposta perdida (timeout)5espera aleatória entre 0 e 200 msPOST /settlements (key K)6200 liquidação original, sem novo débito7Cliente PIXLiquidação BACEN
7

7 passos — reproduza para seguir o fluxo

Como funciona

6 passos

Tentativas com espera crescente.

Esconde cada passo: lembre antes de tocar para revelar.

Vocabulário compartilhado

  1. 01

    pixSubmit gera a idempotencyKey uma vez, antes do loop, e todas as tentativas a enviam

  2. 02

    retryWith executa a operação; falha que errorIsRetryable rejeita (4xx de negócio, erro desconhecido) sobe na hora

  3. 03

    Retentável429, 502, 503, 504, timeout, conexão recusada ou fechada

  4. 04

    backoffDelay sorteia a espera entre 0 e delayBaseMs × 2^(tentativa−1), limitada a delayMaxMs (full jitter); um 429 impõe o Retry-After como mínimo

  5. 05

    Cada tentativa falha sai em log com número, espera e motivo; em maxAttempts, ErrorRetryExhausted carrega a última falha como causa

  6. 06

    O BACEN responde a chave repetida com a liquidação original: o débito acontece uma vez só

Trade-offs

O que se ganha, o que se paga

4 vantagenscada ganho tem um preço4 custos

Vantagens

  • Falha transitória não vira erro para o cliente

  • Jitter espalha as tentativas de clientes que falharam juntos

  • Classificação conservadora nunca retenta o que pode ter escrito

  • Teto de tentativas limita a carga extra

Custos

  • A latência até o sucesso soma as esperas

  • Retry em escrita exige idempotência no destino

  • Erro transitório não mapeado vira falha definitiva

  • Sem circuit breaker em volta, cada chamada ainda gasta todas as tentativas

apps/resiliency/retry-pattern

5 arquivos

src/

  • retry_policy.tsClassificação do erro, backoff com full jitter, teto de tentativas e log
  • client_pix.tsEnvio do PIX com a chave de idempotência fixa entre tentativas
  • bacen_settlement.tsLiquidação em ElysiaJS idempotente por chave, com falhas trocadas em runtime
  • config_retry.tsConfiguração validada do ambiente
  • demo.tsdemo503 transitório, resposta perdida sem débito duplo e saldo insuficiente

Executar · só Bun

  1. bun install# dependências
  2. bun run demo# roda o cenário
  3. bun run test# testes unitários
  4. bun run test:mutation# mutação com Stryker
Requisitos
Bun
Esc

↑ ↓ navegarEnter abrir191 resultados