Kafka garante entrega.

Não garante processamento.

Essa distinção parece simples, mas muita arquitetura quebra exatamente por não tratá-la com a seriedade necessária.

O broker recebeu, replicou, reteve e disponibilizou a mensagem corretamente.

Ótimo.

Isso ainda não prova que seu banco foi atualizado, que a API externa respondeu, que o e-mail foi disparado, que a cobrança aconteceu uma única vez ou que o estado final do negócio ficou consistente.

Entrega e processamento não são a mesma garantia.

Quando o time mistura as duas coisas, começa a cobrar do Kafka uma responsabilidade que é do consumidor.


O que o Kafka garante de verdade

No escopo certo, o Kafka entrega bastante.

Ele sabe:

  • persistir mensagens no log;
  • replicar dados entre brokers;
  • expor leitura ordenada dentro da partição;
  • coordenar avanço de consumo por offset;
  • reentregar registros quando o consumidor falha antes de consolidar sua posição.

Isso é valioso.

Foi justamente essa camada que apareceu no post sobre durabilidade e tolerância a falhas: o cluster pode estar íntegro, a mensagem pode continuar existindo e ainda assim o seu sistema falhar em produzir o efeito esperado.

O ponto central é este:

o Kafka garante transporte e armazenamento dentro do seu modelo.

Ele não observa a semântica real do que sua aplicação fez com a mensagem depois de lê-la.


O que o Kafka não consegue garantir por você

Assim que o evento sai do log e entra no seu código, a responsabilidade muda de mãos.

O Kafka não sabe se:

  • a transação no banco foi concluída;
  • a chamada HTTP realmente funcionou;
  • o retry repetiu efeito colateral;
  • o commit de offset aconteceu cedo demais;
  • a regra de negócio abortou no meio;
  • a aplicação caiu depois de executar metade do fluxo.

Do ponto de vista do broker, nada disso existe como verdade de negócio.

Existe leitura, commit, retenção e protocolo de consumo.

O resto está fora da fronteira que a plataforma consegue proteger.

É por isso que "a mensagem foi entregue" não deveria ser traduzido como "o processamento deu certo".


O lugar onde a confusão nasce

Imagine este fluxo:

  1. o consumer lê um evento de pagamento;
  2. grava uma auditoria no banco;
  3. chama um gateway externo;
  4. atualiza o status do pedido;
  5. confirma o offset.

Agora troque a ordem mental por um incidente real:

  • o consumer leu a mensagem;
  • parte do trabalho aconteceu;
  • a aplicação falhou antes do fluxo terminar;
  • o offset avançou no momento errado ou a operação externa já produziu efeito.

Nesse cenário, o Kafka não “descobre” sozinho o que faltou.

Ele só enxerga a parte que pertence ao seu protocolo.

Foi exatamente esse tipo de armadilha que apareceu nos posts sobre perda lógica no consumer, auto commit mentir e idempotência.

O broker pode estar impecável.

O processamento pode continuar errado.


Offset não é recibo de negócio

Esse ponto merece destaque isolado.

Muita equipe olha para offset commitado e imagina uma confirmação de sucesso.

Não é.

Offset commitado só significa que o consumer registrou uma posição de leitura como próxima referência para retomada.

Ele não carrega, por si só, nenhuma prova de que:

  • o banco persistiu;
  • o efeito externo foi concluído;
  • a operação não será repetida;
  • o estado final ficou consistente.

Se o time trata commit como recibo de processamento, passa a ler o sistema com a semântica errada.

E quando isso acontece, lag baixo, partição avançando e gráfico bonito viram métricas enganosas.

O consumo parece saudável.

O negócio não necessariamente está.


Até exactly-once tem fronteira

Outro ponto que costuma confundir bastante é exactly-once.

Quando bem configurado, ele ajuda muito em fluxos Kafka para Kafka.

Consumir, transformar, publicar resultado e coordenar offsets dentro da transação é uma capacidade poderosa.

Mas isso ainda não transforma banco, cache, e-mail, webhook ou gateway de pagamento em participantes nativos dessa garantia.

Foi por isso que o post sobre exactly-once insistiu tanto no escopo real da promessa.

Exactly-once não apaga a necessidade de idempotência fora do log.

Ele fortalece uma fronteira específica.

Não fecha automaticamente a conta do sistema inteiro.


O que realmente protege processamento

Se processamento importa, a proteção precisa aparecer no desenho do consumidor.

Alguns pilares costumam ser indispensáveis:

  • commit no momento certo, depois do ponto de verdade do processamento;
  • idempotência para tolerar reentrega e repetição;
  • retry com critério, para não amplificar falha;
  • DLT ou DLQ para tirar eventos insolúveis do caminho;
  • observabilidade que meça efeito de negócio, não só avanço de offset;
  • modelagem cuidadosa da fronteira entre Kafka e efeitos externos.

Dependendo do fluxo, isso pode incluir:

  • upsert em vez de insert cego;
  • chave de deduplicação;
  • outbox;
  • processamento assíncrono desacoplado;
  • reconciliação posterior.

Kafka ajuda bastante.

Mas a garantia final de processamento nasce da combinação entre protocolo de consumo e desenho da aplicação.


A pergunta certa não é “a mensagem chegou?”

Essa pergunta é útil, mas é insuficiente.

A pergunta mais madura é:

"qual evidência eu tenho de que o efeito esperado aconteceu do jeito certo, no lugar certo e sem duplicidade indevida?"

Se a única resposta do sistema for "o offset avançou", a arquitetura ainda está olhando para a metade errada do problema.


O ponto que vale fixar

Kafka garante entrega dentro do modelo dele.

Quem garante processamento é o seu consumer.

Se o seu sistema precisa de efeito confiável de negócio, não basta confiar na durabilidade do broker.

É preciso desenhar explicitamente commit, idempotência, retry, tratamento de falhas e fronteiras de consistência.

Porque mensagem entregue e trabalho concluído continuam sendo coisas diferentes.