Kafka e o Primeiro Evento
Garantias: at-least-once, at-most-once, exactly-once
Você aplica garantias de entrega no Kafka com foco em confiabilidade para fluxos de negócio.
Nesta aula você vai
- Diferenciar at-most-once, at-least-once e exactly-once
- Configurar producer e consumer para comportamento previsível
- Escolher estratégia adequada para customer.created
Garantias: at-least-once, at-most-once, exactly-once
Objetivos
- Diferenciar at-most-once, at-least-once e exactly-once
- Configurar producer e consumer para comportamento previsível
- Escolher estratégia adequada para customer.created
Pré-requisitos
- Tópico Kafka configurado
- Producer/consumer básicos funcionando
- Conhecimento de retries e falhas transitórias
Conceito
Garantia de entrega sempre envolve trade-off. at-most-once pode perder mensagem, mas evita duplicata. at-least-once evita perda, mas pode duplicar. exactly-once reduz duplicata e perda, porém aumenta custo e complexidade.
No início de um sistema distribuído, a escolha mais prática costuma ser at-least-once com consumidor idempotente. É robusto, simples de operar e cobre bem eventos de integração como customer.created.
Nesta aula, você configura producer com acks=all e consumidor com commit manual após processamento bem-sucedido para tornar o comportamento explícito.
Estrutura de arquivos
services/
customer-service/src/main/java/.../KafkaCustomerPublisher.java
order-service/app/consumers/customer_created_consumer.py
order-service/app/service/customer_projection_service.py
infra/docker-compose.yml
Passo a passo
- Configurar producer Java com confirmação forte
Properties props = new Properties();
props.put("bootstrap.servers", "kafka:9092");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("acks", "all");
props.put("retries", "5");
props.put("enable.idempotence", "true");
- Configurar consumer Python com commit manual
consumer = KafkaConsumer(
"customer.created.v1",
bootstrap_servers="kafka:9092",
group_id="order-service-customer-group",
enable_auto_commit=False,
auto_offset_reset="earliest",
)
- Processar e commitar somente após sucesso
for msg in consumer:
event = json.loads(msg.value.decode("utf-8"))
try:
projection_service.upsert_customer(event)
consumer.commit()
print(f"commit realizado offset={msg.offset}")
except Exception as exc:
print(f"erro no processamento offset={msg.offset}: {exc}")
- Implementar idempotência simples na projeção
class CustomerProjectionService:
_seen_events = set()
def upsert_customer(self, event: dict):
event_id = event["eventId"]
if event_id in self._seen_events:
return
self._seen_events.add(event_id)
# atualiza projeção local
Como testar
- Subir ambiente:
docker compose -f infra/docker-compose.yml up --build -d kafka customer-service order-service
- Publicar duas vezes o mesmo evento (mesmo
eventId) e verificar idempotência:
docker compose -f infra/docker-compose.yml exec kafka \
kafka-console-producer.sh --bootstrap-server kafka:9092 --topic customer.created.v1
Mensagem enviada duas vezes:
{"eventId":"evt-duplicado-1","customerId":"c-9","email":"c9@aprendi.dev","occurredAt":"2026-07-03T18:20:00Z"}
- Ver logs do consumidor:
docker compose -f infra/docker-compose.yml logs -f order-service
Saída esperada: processamento uma vez e commits sem erro.
Dicas de projeto
- Para integração de domínio, prefira
at-least-once+ idempotência. - Faça commit de offset apenas após persistência concluída.
- Registre
eventId,partitioneoffsetem log. - Teste cenários de falha entre processamento e commit.
Erros comuns
- Usar auto commit com processamento demorado.
- Assumir exactly-once sem validar consumidor.
- Não implementar deduplicação por
eventId. - Ignorar retries do producer.
Resumo
Você aplicou uma estratégia de entrega robusta para o primeiro evento do projeto: producer confiável, commit manual e idempotência. Isso reduz perda de mensagem e prepara o fluxo ponta a ponta.