Recuperação de erros: degradação graciosa em escala

SchemaBridge Team · 2026-01-16 · Resilience, Error Handling, Fault Tolerance

Como lidar com retries e backoffs em escala, e como a resiliência gerenciada evita as "tempestades de retry".

Principais conclusões Uma lógica de retry ingênua amplifica uma indisponibilidade até virar uma tempestade de retry que derruba justamente o serviço que ela está martelando. A resiliência vem de retries limitados — um backoff exponencial curto para falhas HTTP transitórias e um ritmo adaptativo quando um backend sinaliza sobrecarga —, além de rollouts graduais com rollback automático para novas versões de workflow e de ferramentas de recuperação humana (Retry, Resolve, Start over) para tudo o que a automação não deveria decidir.

A "tempestade de retry": por que o tratamento de erros ingênuo falha

Nos primórdios dos sistemas distribuídos, "tratar erros" geralmente significava envolver um trecho de código em um try/catch e talvez adicionar um simples laço while para tentar de novo três vezes. Isso funciona em um ambiente pequeno e isolado, onde as falhas são raras e localizadas. Mas em escala, numa malha de microsserviços interconectados, retries ingênuos são a receita para um colapso sistêmico conhecido como tempestade de retry (Retry Storm, ou "Thundering Herd").

Imagine um cenário em que seu banco de dados principal fica um pouco lento sob carga pesada durante uma promoção de Black Friday. A latência das consultas sobe de 10 ms para 1100 ms. Sua API tem um timeout padrão de 1 segundo. De repente, mil workers concorrentes atingem esse timeout ao mesmo tempo. Todos capturam o erro e, seguindo a lógica do seu laço simples, repetem a consulta imediatamente.

Agora seu banco de dados — que já tinha dificuldade para atender as 1.000 requisições iniciais — recebe de uma vez 1.000 requisições adicionais. A carga dobra instantaneamente. A CPU do banco dispara para 100% e as latências sobem para 5 segundos. Os workers falham de novo e tentam de novo. O sistema entra num ciclo de realimentação positiva de falhas. Na prática, você fez um DDoS na sua própria infraestrutura. Transformou uma pequena degradação de desempenho em uma queda total do sistema.

Abraçando a falha: erros fazem parte da API

Na SchemaBridge, abandonamos a ideia de que erros são "excepcionais". Num mundo orientado a eventos, a falha é tão comum quanto o sucesso. Redes se particionam, pods se comportam de forma errática e APIs de terceiros têm janelas de manutenção. Tratamos a recuperação de erros não como um bloco catch no seu código, mas como um ciclo de vida gerenciado na plataforma — com limites deliberadamente estreitos sobre o que é repetido automaticamente.

Como a SchemaBridge classifica as falhas

Para se recuperar com eficácia, é preciso primeiro entender por que algo falhou. A SchemaBridge toma essa decisão em duas camadas:

| Camada | Falha | O que acontece automaticamente |

| :--- | :--- | :--- |

| Chamada HTTP (Gateway) | 5xx, 429 ou erro de E/S (timeout, conexão resetada) | Repetida dentro do processo, até mais 3 tentativas com backoff exponencial |

| Chamada HTTP (Gateway) | Qualquer outro 4xx (400, 401, 403, 404…) | Não é repetida — uma senha errada nunca vai funcionar na segunda tentativa |

| Etapa (vertex) | Sobrecarga transitória de um backend com rate limit (external_overload) | Redespachada automaticamente, até um orçamento por vertex |

| Etapa (vertex) | Todo o resto | Terminal na primeira tentativa; a execução aparece em vermelho e aguarda um operador |

O padrão é deliberadamente conservador: a falha de uma etapa é permanente, a menos que se prove transitória. Preferimos expor uma falha a uma pessoa a reexecutar silenciosamente um efeito colateral que talvez não seja seguro repetir.

Anatomia de um retry limitado: a matemática do backoff

Backoff exponencial para chamadas HTTP

Quando uma chamada de Gateway encontra um erro transitório, a plataforma não martela o destino a cada segundo. Ela espera exponencialmente mais entre as tentativas.

$$Wait = Base \times 2^{Retry - 1}$$

São quatro tentativas no total, ao longo de cerca de sete segundos. Se o destino responder 429 Too Many Requests com um cabeçalho Retry-After, a plataforma o respeita, com limite de 30 segundos. Essa progressão curta e limitada absorve oscilações de rede sem transformar um serviço em dificuldades numa vítima. Observe que o backoff não é aleatorizado — não há jitter —, então ele foi pensado para suavizar uma oscilação, não para coordenar milhares de clientes independentes.

Redespacho adaptativo para backends sobrecarregados

Um backoff curto é a ferramenta errada para um backend realmente saturado. Nos tipos de etapa com rate limit (etapas de Gateway e agênticas), uma falha por sobrecarga realimenta o controle de admissão por destino da plataforma, que reduz a taxa com que admite trabalho para aquele destino (um controlador AIMD, a mesma ideia que o TCP usa para congestionamento). A etapa que falhou é então redespachada automaticamente por esse mesmo caminho de admissão — por padrão até 3 vezes, configurável por vertex com maxAutoRetries (defina como 0 para uma etapa cujo efeito colateral nunca deva ser reenviado).

{
  "type": "GATEWAY",
  "config": {
    "url": "https://api.example.com/v1/charges",
    "method": "POST",
    "maxAutoRetries": 5
  }
}

Como o ritmo vem do controle de admissão e não de um temporizador fixo, os retries desaceleram exatamente o quanto o destino precisa. Se a sobrecarga durar mais que o orçamento, a etapa falha e a execução aguarda um operador.

Rollback gradual: segurança nos releases de workflows

Às vezes, retries são inúteis. Se uma nova versão de workflow introduz um bug, nenhuma quantidade de retries vai corrigi-lo. É preciso fazer rollback.

A SchemaBridge oferece rollouts graduais com rollback automático para versões de workflow, implementados como um workflow de sistema (gradual_deploy).

Isso limita o raio de impacto de um release de workflow com defeito à fatia de tráfego que ele havia alcançado quando a verificação o detectou. Vale para versões de workflow — não para configuração de infraestrutura — e é uma rede de segurança, não uma garantia: o tráfego que a nova versão recebeu antes de o limite ser atingido ficou exposto mesmo assim.

Recuperação com intervenção humana: o kit de ferramentas do operador

Algumas falhas exigem um cérebro, não um laço. Se um workflow falha porque uma conciliação bancária não bate com o valor da fatura por US$ 0,01, nenhum código pode nem deve decidir o que fazer.

Na SchemaBridge, uma execução assim simplesmente termina como FAILED, com tudo o que um operador precisa para agir:

Isso transforma os "erros" de fonte de pânico e de gambiarras no banco de dados em um workflow operacional padrão.

Cenário ilustrativo: uma indisponibilidade do gateway de pagamento

Considere uma empresa SaaS de assinaturas que processa um grande lote de renovações toda meia-noite. Numa noite, seu gateway de pagamento principal sofre uma indisponibilidade prolongada em uma região.

O jeito antigo

Um sistema legado baseado em simples cron jobs tenta três vezes quando o gateway cai e depois marca as assinaturas como "Falhou / Pagamento recusado". Quando os engenheiros acordam, contas de clientes podem ter sido desativadas porque o sistema concluiu que os pagamentos foram recusados, quando na verdade o gateway apenas estava fora do ar. A fila de suporte enche, e o churn vem logo depois dos e-mails de "Conta cancelada".

O jeito SchemaBridge

Agora imagine o mesmo motor de cobrança rodando na SchemaBridge, com honestidade.

1. Retries limitados: quando os 503 começam, cada chamada de cobrança é repetida com um backoff curto. Uma oscilação é absorvida; uma indisponibilidade de horas, não — essas execuções de renovação falham.

2. Falha não é decisão: como uma etapa que falhou interrompe a sua execução em vez de seguir por um caminho de "recusado", ninguém tem a conta cancelada por uma indisponibilidade interpretada erroneamente como recusa. As execuções que falharam ficam no monitor, em vermelho, com o erro do gateway anexado.

3. A recuperação é uma ação em lote: quando o gateway volta a ficar saudável, um operador seleciona as execuções que falharam e as repete em lote.

O resultado esperado

A indisponibilidade ainda acontece, e alguém ainda precisa agir pela manhã. O que muda é o estrago: nenhum cancelamento indevido, nenhum e-mail espúrio e uma recuperação que é uma única ação em lote em vez de uma limpeza no banco de dados. Esse é o valor de negócio da resiliência.

Checklist de especialista para um design tolerante a falhas

Para construir um sistema resiliente, siga estas heurísticas:

1. Planeje como desfazer cada escrita: se você cria um registro, saiba como o excluiria ou arquivaria em caso de falha — mesmo que esse desfazer seja uma etapa disparada por uma pessoa. A simetria é a chave da consistência.

2. Adicione jitter aos retries dos clientes que você controla: quando muitos clientes independentes repetem no mesmo cronograma, a aleatoriedade impede que eles se sincronizem em manada.

3. Prefira uma execução parada a um caminho errado: não deixe uma falha de infraestrutura se passar por um resultado de negócio. Uma execução que falhou e aguarda uma pessoa é melhor que uma silenciosamente errada.

4. Audite seus caminhos de erro: costumamos testar o "caminho feliz" e ignorar o "caminho da falha". Em um ambiente de staging, aponte uma etapa para um endpoint que retorne 503 e 400 e confirme que a execução se comporta como você espera em cada caso.

Conclusão: a falha é uma oportunidade para a resiliência

Recuperação de erros não é sobre evitar bugs; é sobre evitar desastres. Ao limitar os retries automáticos, deixar que a sobrecarga desacelere o sistema em vez de provocar um estouro e dar aos operadores ferramentas de recuperação precisas, você ganha liberdade para construir integrações complexas sem medo da "tempestade de retry".

Parte da nossa série Building the Bridge. Veja também: Infraestrutura como workflow, sobre o gerenciamento de recursos de nuvem com lógica visual.

Explorar