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?".