Execução durável: o que é e como funciona na prática
skail · 2026-09-11 · 5 min
Um checkout comum tem quatro passos em sequência: cobrar o cliente, reservar o estoque depois que o pagamento é confirmado, emitir a nota fiscal e mandar um e-mail com a nota e os dados de entrega. Em produção, uma compra passa pela cobrança e pela reserva e trava na emissão da nota, porque a SEFAZ está fora do ar. Execução durável é o nome do conjunto de técnicas que resolve esse tipo de situação.
A SEFAZ é só uma das causas possíveis. O orquestrador de contêineres pode derrubar o pod no meio da emissão e subir outro no lugar, ou uma oscilação de rede pode engolir a resposta. Em qualquer desses casos, o cliente já pagou e o estoque já está reservado, mas o processo perdeu a noção de onde estava.
Recomeçar do zero significa cobrar o cliente duas vezes, e desistir deixa um pedido pago sem nota e sem envio. A saída é continuar do ponto exato da falha, sem refazer o que já deu certo. Para quem prefere o formato em vídeo, a explicação completa está logo abaixo.
A ideia central da execução durável: checkpoints
Reduzido ao essencial, o problema é este. Um serviço A chama um serviço B e a resposta não volta. B pode ter processado ou não. Talvez tenha batido no rate limit, talvez um deploy tenha derrubado a execução no meio do caminho. A fica sem saber o que aconteceu.
A execução durável responde a isso salvando a evolução do processo em pontos de checagem, os checkpoints, para que ele continue de onde parou. A analogia mais simples vem do videogame: você avança fase por fase e morre no chefão final. Com checkpoint, volta para o último ponto salvo e joga só o trecho que faltava, enquanto sem ele a fase inteira recomeça.
Tudo o que vem a seguir (replay, retry, idempotência, determinismo, hibernação e paralelismo) é consequência dessa ideia.
Registro de progresso e replay: retomar em outro host sem repetir passos
Tudo começa no registro das atividades. Antes de iniciar o próximo passo, o sistema grava o que executou, com quais argumentos e qual foi o resultado. No checkout, isso significa registrar que o cartão daquele pedido foi cobrado, com o valor e a autorização devolvida pelo gateway, antes de tocar no estoque.
Com esse histórico gravado, existe o replay. Imagine que o processo roda no host A e o host A some. Ele pode ter sido desprovisionado, o sistema operacional pode ter matado o processo por falta de memória (o famoso OOM kill), qualquer coisa. O processo já tinha cobrado o cartão e reservado o estoque quando caiu na emissão da nota.
O replay reconstrói essa execução em outro host, desde o começo, sem repetir o que já foi feito. A cobrança consta no registro, então não acontece de novo, e o mesmo vale para a reserva de estoque. Na prática, a execução segue a partir da emissão da nota.
Tanto faz se a retomada acontece no mesmo host ou em um completamente diferente. Quem guarda o estado é o registro, e o host vira um detalhe.
Retry e idempotência: como chegar ao efeito de exatamente uma vez
Replay e retry costumam ser confundidos. O replay reconstrói uma execução inteira a partir do histórico, enquanto o retry repete um passo específico que falhou: tenta, falha, tenta de novo, até funcionar ou esgotar as tentativas. O intervalo entre uma tentativa e outra costuma crescer a cada falha, técnica conhecida como exponential backoff (recuo exponencial).
Todo retry opera sob uma de três garantias de entrega:
- At-most-once (no máximo uma vez): o passo roda zero ou uma vez. Se falhar, pode simplesmente não acontecer.
- At-least-once (pelo menos uma vez): zero execuções não é aceitável, então o passo pode rodar mais de uma vez para garantir que aconteceu.
- Exactly-once (exatamente uma vez): mesmo que o comando chegue repetido, o efeito acontece uma única vez.
O exactly-once depende de outra característica da execução durável, a idempotência. Pense no passo de cobrança. O sistema faz um POST no endpoint do gateway de pagamento, o gateway cobra o cliente e, na hora de responder, a rede cai. A resposta nunca chega, o sistema conclui que deu erro e faz o retry. Sem idempotência, o gateway trata a segunda requisição como nova e cobra o cliente duas vezes.
Com idempotência, a requisição leva uma chave de idempotência que identifica aquela cobrança específica. No retry, o gateway reconhece a chave, sabe que já processou aquela operação e devolve a mesma autorização, sem cobrar de novo. É a combinação de retry com chave de idempotência que entrega, na prática, o efeito de exatamente uma vez.
Determinismo: por que o replay precisa dar o mesmo resultado
O replay só funciona se reexecutar o processo levar aos mesmos resultados. O risco está em tudo que vem de fora do código: consulta ao banco, leitura de arquivo, chamada de API, leitura da data e hora e até chamada a um LLM. Cada execução pode trazer um valor diferente. No caso do LLM a coisa fica evidente, porque o mesmo prompt pode devolver outra resposta e ainda consumir tokens de novo.
Primeiro, um exemplo determinístico. Uma regra de negócio manda cotações acima de 5 milhões por um caminho e as de até 5 milhões por outro. O valor vem de um método que busca a cotação no banco. Se o resultado dessa busca fica salvo no registro de progresso, todo replay lê o valor gravado em vez de consultar o banco outra vez. A execução segue sempre pelo mesmo caminho, não importa quantas vezes seja refeita.
Agora a quebra. Uma transação começa às 9h59, e as regras de antes das 10h valem para ela. Vários passos já rodaram seguindo esse caminho. Mais adiante, o código tem uma bifurcação que lê o relógio para decidir entre o caminho A (antes das 10h) e o caminho B (depois das 10h). Antes de chegar lá, a aplicação cai.
O replay acontece às 10h05, lê o relógio de novo e vai para o caminho B. A mesma transação fica com metade dos passos numa regra e metade em outra. A regra prática é obter qualquer informação externa uma única vez, principalmente data e hora, registrar o resultado e ler do registro em todos os replays seguintes.
Hibernação: esperar horas ou meses sem ocupar recurso
Muitos processos precisam parar e esperar alguém. O caso típico é o human in the loop (humano no ciclo), quando a execução chega num ponto em que depende da aprovação de um pedido. Essa aprovação pode vir de outra tela, de outro sistema, de uma mensagem no WhatsApp ou de um e-mail.
Numa aplicação com execução durável, o processo hiberna nesse ponto. Ele libera a thread e o slot que ocupava no host, e registra onde parou e qual evento está esperando. Quando o evento externo chega, o processo acorda e continua dali, no host A ou em qualquer outro.
A hibernação só é segura por causa de tudo que veio antes. Registro de progresso, replay, idempotência e determinismo juntos garantem que a execução pode dormir por horas, dias ou meses e acordar sem refazer nada e sem mudar de rumo.
Paralelismo durável: esperar todos ou o primeiro que responder
A última característica é disparar várias tarefas em paralelo e segurar o fluxo principal até elas terminarem. Existem dois formatos.
No primeiro, todas as tarefas precisam terminar. Um pedido que exige a aprovação de cinco pessoas dispara as cinco solicitações ao mesmo tempo, e a execução só avança quando chega a última aprovação.
No segundo, a primeira tarefa que terminar decide. O exemplo clássico envolve prazo. Um usuário ganha um período premium que dura até ele assinar o plano pago ou até completar 30 dias, o que vier primeiro. Se a assinatura chega antes, o acesso continua; se o prazo vence primeiro, o acesso é bloqueado. As duas condições concorrem, e a que vencer define o caminho do código.
Como as peças se encaixam no checkout
Voltando ao cenário do começo. Com o progresso registrado, a queda do pod na emissão da nota vira um replay em outro host que pula a cobrança e a reserva de estoque. A chamada à SEFAZ entra em retry com backoff até o serviço voltar, e a chave de idempotência impede que uma nota emitida sem resposta seja emitida de novo. Se o processo leu a data e hora em algum passo, esse valor está no registro e o replay usa o mesmo.
O mesmo raciocínio vale para agentes de IA. Ferramentas como Codex, Claude Code, Hermes e OpenClaw rodam longas cadeias de iterações, e cada chamada ao modelo custa tempo e tokens. Perder esse progresso numa queda sai caro, e é aí que a execução durável faz mais diferença. Esse é o assunto do próximo conteúdo da série.
A skail implementa essas primitivas em .NET. A espera por evento externo é o WaitForEvent, e a corrida entre condições é o WhenAny. A documentação da skail mostra como aplicar cada uma num workflow real.