Pular para o conteúdo principal
Sumário do livro

Parte V — Java e Spring Boot

Producer com Spring Kafka

KafkaTemplate na prática — topic, key, value, serialização, callbacks, headers e correlationId.

Nesta página

Os capítulos anteriores explicaram conceitos que valem para qualquer client Kafka. A partir daqui, a Parte V mostra como esses conceitos aparecem em código Java real, usando Spring Kafka — começando pelo lado que publica eventos.

KafkaTemplate

KafkaTemplate

KafkaTemplate<K, V> é a abstração do Spring Kafka para publicar mensagens — o equivalente, para produção de eventos, do JdbcTemplate para acesso a banco. Ele encapsula o KafkaProducer nativo do client Java, expondo uma API mais simples e integrada ao restante do Spring (injeção de dependência, propriedades de configuração, métricas).

@Service
public class PagamentoEventPublisher {

    private final KafkaTemplate<String, PagamentoAprovadoEvent> kafkaTemplate;

    public PagamentoEventPublisher(KafkaTemplate<String, PagamentoAprovadoEvent> kafkaTemplate) {
        this.kafkaTemplate = kafkaTemplate;
    }

    public void publicar(PagamentoAprovadoEvent evento) {
        kafkaTemplate.send("pagamentos.aprovados", evento.getContaId(), evento);
    }
}

Topic, Key e Value

O send mais comum recebe três argumentos: o tópico, a key (Capítulo 4 — decide a partition de destino e a ordenação relativa) e o value (o payload do evento). Overloads com dois argumentos (send(topic, value)) publicam sem key, sujeitos à distribuição aproximadamente uniforme entre partitions.

Nunca esqueça a key em eventos que exigem ordenação

Um refactor que remove a key "para simplificar o código" silenciosamente destrói a ordenação relativa entre eventos da mesma entidade (Capítulo 4). Trate a key como parte do contrato do tópico, documentada junto com ele — não como um detalhe implícito do código do producer.

Serialização

O Spring Kafka delega a serialização de key e value a classes Serializer<T> configuradas via spring.kafka.producer.key-serializer / value-serializer. As opções mais comuns em produção:

Estratégias de serialização

FormatoCaracterística
JSON (JsonSerializer)Simples, legível, mas sem verificação de schema — mudanças incompatíveis só quebram em runtime
Avro (com Schema Registry)Schema versionado e compatibilidade verificada em build/publish time; payload binário compacto
ProtobufSimilar ao Avro em garantias de schema, com forte tipagem no Java gerado a partir do .proto

Times que ainda não têm Schema Registry geralmente começam com JSON e migram para Avro/Protobuf quando o número de consumidores cresce o suficiente para que mudanças incompatíveis de payload se tornarem um risco real de quebra entre serviços de times diferentes.

Callbacks: tratando o resultado do envio

send() é assíncrono — retorna um CompletableFuture<SendResult<K, V>> imediatamente, sem esperar a confirmação do broker. Ignorar esse retorno significa não saber se a publicação teve sucesso.

KafkaTemplate.send(topic, key, value)BrokeronSuccess(SendResult)ack recebidoonFailure(Throwable)falha ao publicar
KafkaTemplate.send() é assíncrono; o resultado chega via callback, onSuccess com o SendResult ou onFailure com a exceção.
kafkaTemplate.send("pagamentos.aprovados", evento.getContaId(), evento)
    .whenComplete((result, exception) -> {
        if (exception != null) {
            log.error("Falha ao publicar evento de pagamento", exception);
        } else {
            log.debug("Evento publicado no offset {}", result.getRecordMetadata().offset());
        }
    });

"Chamei o send(), então o evento foi publicado"

Chamar send() apenas enfileira a mensagem para envio assíncrono — não garante que ela chegou ao broker. Sem tratar o callback (ou usar .get() de forma síncrona, com o custo de latência que isso implica), falhas de publicação passam silenciosamente despercebidas, exatamente o cenário de dual write discutido no Capítulo 12.

Headers e correlationId

Além de key e value, uma mensagem Kafka carrega headers — metadados arbitrários, tipicamente usados para rastreabilidade e integração entre serviços, sem poluir o payload de negócio.

ProducerRecord<String, PagamentoAprovadoEvent> record =
    new ProducerRecord<>("pagamentos.aprovados", evento.getContaId(), evento);
record.headers().add("correlationId", correlationId.getBytes(StandardCharsets.UTF_8));

kafkaTemplate.send(record);

Dica de entrevista

Mencionar correlationId propagado via headers demonstra conhecimento prático de observabilidade em sistemas distribuídos: ele permite rastrear uma requisição desde a chamada HTTP original, passando pelo evento Kafka, até os consumers que o processam — essencial para debugar um fluxo que atravessa múltiplos serviços (aprofundado no Capítulo 15).

Tratamento de falhas do producer

Falhas de publicação se dividem nas mesmas categorias do Capítulo 9: transitórias (broker temporariamente indisponível — o client Kafka já faz retry automático internamente, configurável via retries e delivery.timeout.ms) e permanentes (mensagem maior que max.request.size, serialização que lança exceção). O callback onFailure é o lugar certo para logar, alertar, ou — em casos críticos — persistir a mensagem falha para reenvio manual, já que o send() não bloqueia a aplicação esperando esse resultado.

Como aparece em entrevistas

"Como você garantiria que um evento foi publicado com sucesso no Kafka?" é a pergunta prática mais comum sobre producer. A resposta esperada cita o retorno assíncrono do send(), o tratamento do callback (não apenas chamar e seguir em frente), e — para o cenário de consistência com banco de dados — o outbox pattern do Capítulo 12, já que nenhum callback de producer resolve o problema de dual write sozinho.

Relação com sistemas reais

Publicando compra autorizada com rastreabilidade

O autorizacao-service, ao aprovar uma compra no cartão, publica o evento CompraAutorizada usando cartaoId como key (ordenação por cartão, Capítulo 4), propaga o correlationId da requisição HTTP original via header, e trata o callback do send() registrando uma métrica de falha de publicação — que alimenta um alerta se a taxa de falha ultrapassar um limiar (Capítulo 15).

Resumo

KafkaTemplate encapsula o producer Kafka no Spring Boot: send(topic, key, value) publica de forma assíncrona, retornando um CompletableFuture que deve ser tratado via callback para saber se a publicação teve sucesso. Serialização (JSON, Avro, Protobuf) e headers (como correlationId, para rastreabilidade) completam o contrato de uma publicação bem-feita. Nenhum desses mecanismos, isoladamente, resolve consistência com o banco de dados — para isso, o padrão é o outbox (Capítulo 12).

Pode vir a seguir

Prováveis follow-ups: "o que acontece se o send() falhar silenciosamente sem callback tratado?" e "como você propagaria um correlationId de uma chamada HTTP até o consumer do outro lado do Kafka?".