Início › Glossário › Exactly-once vs at-least-once
Glossário

O que é Exactly-once vs at-least-once?

Em automações, at-least-once significa que um evento pode ser processado mais de uma vez (duplicidades acontecem); exactly-once é a promessa de processar uma única vez, difícil de garantir ponta a ponta; at-most-once evita duplicar, mas pode perder eventos. Na prática, a solução é desenhar idempotência, deduplicação e retries com segurança, em vez de confiar em “exactly-once”.

Os 3 modelos de entrega/processamento (sem romantizar)

Esses termos aparecem em filas, streaming, webhooks e iPaaS, mas quase sempre descrevem um “comportamento esperado”, não uma garantia absoluta em todo o caminho (origem → rede → ferramenta → API de destino).

O ponto crítico: rede falha, timeouts existem, provedores repetem eventos, e sua automação pode reiniciar no meio. Resultado: duplicidade ou perda — e você precisa escolher qual é o “mal menor” por etapa.

ModeloO que tenta garantirO que pode dar erradoQuando faz sentido
At-least-onceProcessar pelo menos uma vezPode processar 2+ vezes (duplicar cobrança, duplicar lead, enviar 2 mensagens)Integrações com retry automático, webhooks com reentrega, filas com ack/retry
At-most-onceProcessar no máximo uma vezPode perder eventos (timeout e ninguém reenvia)Casos em que duplicidade é pior que perda e existe reconciliação depois
Exactly-onceProcessar exatamente uma vezÉ difícil garantir ponta a ponta; geralmente vira “efetivamente uma vez” com idempotência + transaçõesFluxos críticos onde vale investir em desenho robusto (pagamentos, estoque, notas)

Por que duplicidade acontece (mesmo quando “não era pra acontecer”)

Na automação do dia a dia, duplicidade nasce de cenários bem comuns: o webhook chega duas vezes, o provedor reenvia porque não recebeu 200 rápido, a ferramenta faz retry após um 429/500, o workflow cai depois de executar a ação mas antes de registrar o sucesso, ou você tem dois workers concorrentes.

Um detalhe que pega muito em operações no Brasil: integrações com APIs que oscilam, somadas a timeouts agressivos e retries “silenciosos”. Se você não desenha idempotência, você só descobre a duplicidade quando vira problema (cliente reclamando, estoque errado, cobrança duplicada).

  • Reentrega de webhook por timeout (você processa, mas responde tarde)
  • Retry automático por erro 429/5xx (a ação anterior pode ter sido aplicada parcialmente)
  • Concorrência (dois workers pegam o mesmo evento ou eventos equivalentes)
  • Eventos “equivalentes” com IDs diferentes (o provedor manda update + create com payload parecido)
  • Reprocessamento manual sem dedupe (a equipe clica em “executar de novo” e pronto)

O que fazer na prática: “exactly-once efetivo” com idempotência

Para a maioria das automações, o caminho realista é aceitar at-least-once e tornar suas ações idempotentes: se o mesmo evento chegar de novo, seu sistema reconhece e não aplica efeitos duplicados.

Isso não é teoria: é o que evita cobrança duplicada, criação repetida de tickets, e mensagens repetidas no WhatsApp.

  • Use uma idempotency key: um identificador determinístico por evento/ação (ex.: event_id do webhook, ou hash de campos-chave).
  • Armazene a key num lugar confiável (banco/Redis/planilha — escolhendo pela criticidade) com TTL quando fizer sentido.
  • Faça a checagem antes da ação (read-before-write) e, se possível, garanta unicidade (unique constraint) para bloquear corrida.
  • Responda rápido ao webhook (200/202) e processe assíncrono quando a tarefa for pesada.
  • Separe “efeito externo” (enviar mensagem/cobrar/criar pedido) de “log/telemetria”; se cair no meio, você consegue retomar com segurança.

Padrões úteis que resolvem 80% dos incidentes

Você não precisa transformar toda automação em um projeto de engenharia distribuída. Mas alguns padrões pagam o investimento rápido, principalmente quando o fluxo mexe com dinheiro, estoque ou comunicação com cliente.

ProblemaPadrãoComo aplicar (exemplo simples)
Duplicar ação (ex.: cobrar 2x)IdempotênciaAntes de cobrar, checar se (pedido_id + valor + data) já foi processado; se sim, sair
Cascata de retriesBackoff + limite + circuit breakerApós 3 falhas, pausar rota e mandar para fila/pendência de revisão
Eventos travados ou poison messageDLQ (dead-letter queue) / quarentenaDepois de N tentativas, isolar o evento para inspeção e correção
Inconsistência por passos múltiplosSaga / compensaçãoSe criou pedido e falhou nota, marcar “pendente” e agendar compensação/retry

Como decidir: duplicar ou perder (qual é o menor risco?)

Essa decisão é menos técnica e mais de negócio. Para cobrança: duplicar costuma ser inaceitável, então você investe em idempotência forte. Para um relatório interno: perder 1 execução pode ser tolerável, desde que rode de novo amanhã.

Uma regra prática: se o efeito é irreversível ou caro (dinheiro, reputação, bloqueio de conta), trate como at-least-once + idempotência. Se o efeito é recalculável (relatórios), dá para aceitar modelos mais simples.

  • Pagamentos/cobrança: priorize não duplicar (idempotência + reconciliação).
  • Mensagens ao cliente: priorize não repetir (dedupe + janela de tempo).
  • Sincronização de estoque: priorize consistência (logs, retries controlados, reconciliação periódica).
  • Relatórios: priorize robustez e observabilidade (se falhar, reexecuta).

Perguntas frequentes

Ferramentas de automação no-code oferecem exactly-once de verdade?
Raramente como garantia ponta a ponta. O comum é elas operarem em modo at-least-once (com retries) e deixarem para você resolver idempotência no desenho do fluxo e no sistema de destino. Alguns conectores até têm dedupe parcial, mas não dá para assumir que cobre todos os casos.
Como criar uma idempotency key quando o webhook não vem com event_id?
Você pode derivar uma key determinística a partir de campos estáveis do evento (ex.: tipo + id do objeto + timestamp arredondado + valor) ou criar um hash do payload “normalizado”. O cuidado é evitar colisões e garantir que eventos realmente diferentes não virem a mesma key.
Responder 202 no webhook ajuda a evitar duplicidade?
Ajuda indiretamente: ao responder rápido (200/202), você reduz a chance de reentrega por timeout. Mas não elimina duplicidade, porque o provedor pode reenviar por outros motivos (retries próprios, falhas de rede, replays). Ainda assim, responder rápido e processar assíncrono é um bom padrão.
Se eu usar fila (RabbitMQ/SQS/Redis), acabou o problema?
Não. Fila normalmente te dá at-least-once com mais controle (ack, retry, DLQ), o que é ótimo. Mas duplicidade ainda pode existir (reentrega após timeout, consumer crash). A diferença é que fica mais fácil isolar, reprocessar e auditar — desde que você trate idempotência no consumidor.

Termos relacionados

← Ver glossário completo