CDC (Change Data Capture): capturar cada INSERT/UPDATE/DELETE do banco e publicar como evento. Debezium lê o transaction log (WAL no Postgres, binlog no MySQL, CDC tables no SQL Server) e publica no Kafka. Casado com Outbox pattern, é a solução madura para event publishing sem polling.

Fluxo end-to-end

AppINSERT outboxPostgreSQLWAL (logical)DebeziumKafka ConnectKafka topicmtg.ordersSearchCacheGraph KGreads WAL

Passo a passo

  1. App faz INSERT na tabela outbox_messages (mesma transação do write de domínio)
  2. PostgreSQL grava no WAL (write-ahead log) usando plugin pgoutput (logical decoding)
  3. Debezium (Kafka Connect plugin) lê o WAL via replication slot, traduz pra JSON/Avro
  4. Kafka recebe o evento no tópico configurado (uma row da outbox → uma mensagem)
  5. Consumers processam o evento: cache, search, knowledge graph, etc.

Anatomia de um evento Debezium

{ "schema": { ... }, "payload": { "before": null, "after": { "id": "550e8400-e29b-41d4-a716-446655440000", "aggregateid": "order-123", "aggregatetype": "Order", "type": "OrderCreated", "payload": "{\"orderId\":\"order-123\",\"total\":42.5}" }, "source": { "version": "2.5.0", "connector": "postgresql", "name": "mtg", "ts_ms": 1718360400123, "db": "mtg", "schema": "public", "table": "outbox_messages", "txId": 9281, "lsn": 23874091 }, "op": "c", "ts_ms": 1718360400125 } }

A estrutura before/after/op é canônica do Debezium:

  • op = "c" — create (INSERT)
  • op = "u" — update (UPDATE, com before e after)
  • op = "d" — delete (DELETE, com before; value=null no Kafka)
  • op = "r" — read (snapshot inicial)
SMT (Single Message Transform) Outbox achata essa estrutura para o consumer ler só o payload, não o envelope Debezium completo. É praticamente obrigatório para o padrão Outbox + Debezium.