Pular para o conteúdo principal

Pergunta 42 de 50

Como evitar processamento duplicado?

SêniorTech Lead

Pergunta

"Na prática, como você evitaria processamento duplicado de mensagens em um consumer Kafka?"

O que o entrevistador quer avaliar

A pergunta mais aplicada de toda essa seção — quer ver o padrão de implementação real, com atenção específica à atomicidade sob concorrência, não só "eu uso um ID único".

Resposta rápida

Uso um eventId único por evento (gerado pelo producer), e no consumer, verifico e insiro esse eventId em uma tabela de controle (eventos_processados) com constraint de unicidade — na mesma transação que aplica o efeito de negócio. Se a inserção falhar por duplicidade, ignoro o evento com segurança.

Resposta nível Sênior

O ponto crítico é a atomicidade: a checagem de "já processei esse eventId?" e a aplicação do efeito (creditar, debitar, gravar) precisam acontecer na mesma transação de banco. Se forem passos separados — uma consulta seguida de uma atualização —, existe uma janela de corrida onde duas execuções concorrentes podem checar "não existe" ao mesmo tempo e aplicar o efeito duas vezes antes que qualquer uma grave o eventId. A constraint de unicidade do banco, não uma checagem em código de aplicação, é a garantia real. Para operações já naturalmente idempotentes (um upsert que sempre grava o mesmo valor final), esse controle explícito pode ser dispensado — mas para operações que acumulam estado (creditar, incrementar), ele é obrigatório.

Explicação aprofundada

Veja "O padrão: eventId + constraint de unicidade" e "Atomicidade" no Capítulo 11.

Exemplo financeiro

@Transactional
public void creditarPix(PixRecebidoEvent evento) {
    try {
        eventosProcessadosRepository.insert(evento.getEventId());
    } catch (DataIntegrityViolationException e) {
        return; // já processado
    }
    contaRepository.creditar(evento.getContaId(), evento.getValor());
}

"Basta checar se o ID já existe antes de processar"

Checagem prévia sem estar na mesma transação do efeito é vulnerável a condição de corrida. A resposta completa sempre menciona a atomicidade via transação — não apenas a existência de um identificador único.

Pode vir a seguir

Prováveis follow-ups: "e se dois consumers processarem o mesmo evento ao mesmo tempo?" e "como isso se relaciona com o Outbox Pattern?".