← Voltar ao blog

Como projetar consumidores idempotentes

Em sistemas orientados a eventos, duplicação é uma condição normal. Idempotência evita que uma nova entrega gere um novo efeito.

·
  • #eventos
  • #idempotência
  • #kafka
  • #filas

Em filas e streams, a pergunta prática não é se uma mensagem pode aparecer duas vezes. É o que acontece quando ela aparece. Um consumidor pode terminar o efeito no banco e cair antes de confirmar o processamento; a plataforma então entrega a mesma mensagem novamente. Isso é comportamento esperado em sistemas at-least-once.

Idempotência significa que processar a mesma intenção mais de uma vez produz o mesmo estado observável que processá-la uma vez. Ela não exige que a mensagem deixe de duplicar. Ela torna a duplicação segura.

Comece pela identidade da operação

Todo evento que pode produzir efeito precisa carregar uma identidade estável: um event_id, uma chave de negócio ou uma combinação de origem e versão. Essa chave não deve ser gerada pelo consumidor, pois ela precisa ser igual em todas as entregas da mesma intenção.

Uma forma comum é manter uma tabela de processamentos com uma restrição única pela chave de idempotência. A gravação do efeito e o registro de processamento precisam acontecer na mesma transação. Caso contrário, existe uma janela em que o evento é marcado como processado, mas seu efeito não foi persistido — ou o contrário.

Não confunda deduplicação com correção de negócio

Um cache de IDs recentes pode reduzir trabalho, mas não é suficiente para operações que não podem ser duplicadas. Ele expira, pode ser perdido e normalmente não participa da transação de negócio.

Também vale separar duas situações:

  • duas entregas do mesmo evento: descarte a segunda;
  • dois eventos diferentes que tentam alterar o mesmo recurso: aplique as regras de concorrência, versão ou ordenação do domínio.

Idempotência não decide se um pedido cancelado pode ser pago depois. Essa é uma regra de negócio e pode exigir controle de versão, uma máquina de estados ou serialização por chave.

Pense no efeito fora do banco

Se o consumidor envia um e-mail, cobra um cartão ou chama uma API, uma transação local não cobre esse efeito. Use chaves idempotentes na API externa quando houver suporte; caso não haja, registre a intenção e crie um processo de reconciliação. A promessa de “exactly once” raramente atravessa banco, broker e um terceiro ao mesmo tempo.

Por fim, exponha a decisão. Conte mensagens duplicadas, conflitos de chave, reprocessamentos e efeitos compensados. Uma estratégia de idempotência que não aparece na observabilidade é difícil de confiar durante a recuperação de um incidente.