Pular para o conteúdo principal

PIX recebido

Topologia de tópicos, escolha de key, idempotência, retry, DLQ, replay e observabilidade em um fluxo de recebimento de PIX.

Este estudo de caso descreve, de ponta a ponta, como um banco digital modela o recebimento de um PIX como um fluxo orientado a eventos — cobrindo as decisões que normalmente aparecem em entrevista quando o entrevistador pede "descreva um sistema real que você projetaria com Kafka".

O evento de domínio

Quando o Sistema de Pagamentos Instantâneos (SPI) do Banco Central confirma a liquidação de um PIX, o serviço responsável por essa integração publica um evento PixRecebido — um fato que já aconteceu, não um comando.

{
  "eventId": "8f14e45f-...",
  "endToEndId": "E00000000202401010000abcdef12345",
  "contaId": "acc_9182734",
  "valor": 15000,
  "moeda": "BRL",
  "pagador": { "nome": "...", "documento": "..." },
  "recebidoEm": "2026-07-31T14:02:11Z"
}

Topology de tópicos

Tópico e configuração

ItemDecisão
Tópicopix.recebido
KeycontaId
Partitions24 (dimensionadas para o pico de recebimento, não para o volume médio)
Replication factor3
Retention7 dias (suficiente para replay operacional; auditoria de longo prazo fica em um data lake, não no tópico)

Por que a key é contaId

Dica de entrevista

A escolha da key não é sobre distribuir uniformemente — é sobre quais eventos precisam ficar ordenados entre si. Todos os eventos da mesma conta (PIX recebido, PIX enviado, bloqueio de saldo) devem cair na mesma partition para que os consumidores processem-os na ordem correta. Usar eventId como key, por exemplo, distribuiria melhor entre partitions, mas destruiria a ordenação por conta — um erro comum de quem otimiza para throughput sem entender o requisito de ordenação.

Consumidores independentes

ProducerTopic: pagamentosPartition 0Partition 1Partition 2Consumer Group: notificacao-serviceConsumer 0Consumer 1Consumer 2
Múltiplos Consumer Groups leem o mesmo tópico pix.recebido de forma independente.
  • saldo-service: credita o valor na conta, dentro de uma transação idempotente (ver abaixo).
  • notificacao-service: envia push "Você recebeu um PIX de R$ 150,00".
  • extrato-service: grava o lançamento no extrato para consulta futura.
  • antifraude-service: avalia o recebimento contra regras de risco (ex.: muitos PIX de contas novas em curto intervalo).

Cada um desses é um Consumer Group independente. Uma lentidão no antifraude-service não atrasa o crédito do saldo — eles avançam offsets de forma totalmente desacoplada.

Idempotência

Por que idempotência é obrigatória aqui

Garantias de entrega at-least-once (a configuração mais comum em produção) implicam que o mesmo evento PixRecebido pode ser entregue mais de uma vez ao saldo-service — por exemplo, após um rebalance ou um retry de commit. Sem proteção, isso creditaria o mesmo PIX duas vezes.

O saldo-service mantém uma tabela eventos_processados com uma constraint de unicidade em eventId. Antes de aplicar o crédito, ele tenta inserir o eventId; se a inserção falhar por violação de unicidade, o evento já foi processado e a operação é ignorada — a checagem e a aplicação do crédito acontecem na mesma transação de banco, garantindo atomicidade mesmo sob concorrência.

Retry e DLQ

Se o saldo-service falhar ao processar um evento (ex.: banco de dados indisponível momentaneamente), o erro é tratado como transitório: o Spring Kafka reprocessa com backoff exponencial. Depois de um número configurado de tentativas, o evento é publicado no tópico pix.recebido.dlq (Dead Letter Topic) para investigação manual — sem bloquear o processamento dos eventos seguintes na mesma partition (evitando o efeito "poison pill").

Replay

Se um bug no extrato-service gerar lançamentos com valor errado, a correção envolve: (1) corrigir o bug, (2) resetar o offset do Consumer Group extrato-service para o início do intervalo afetado (respeitando a retenção de 7 dias) e (3) deixar o serviço corrigido reprocessar os eventos, reconstruindo os lançamentos do extrato do zero para esse intervalo — sem qualquer interação com o saldo-service, notificacao-service ou antifraude-service, que não são afetados pelo replay de outro grupo.

Observabilidade

Métricas monitoradas

MétricaPor quê
Consumer lag por grupoDetecta se antifraude ou extrato estão ficando para trás do volume recebido
Taxa de mensagens na DLQSinaliza falhas persistentes que exigem investigação
Latência producer → consumerTempo entre a confirmação do PIX e a atualização de saldo, crítico para experiência do usuário
correlationId/eventId nos logsPermite rastrear um PIX específico por todos os serviços que o processaram

Resumo

O fluxo de PIX recebido ilustra por que Kafka é escolhido para esse tipo de problema: um único evento de domínio, key escolhida para preservar ordenação por conta, múltiplos consumidores independentes, idempotência obrigatória por causa de garantias at-least-once, DLQ para isolar falhas persistentes e replay como ferramenta de correção — tudo isso sem acoplar o serviço que recebe o PIX aos serviços que reagem a ele.