NATS JetStream pra outbox, com o mínimo de cerimônia

Padrão outbox sem Kafka, sem Debezium, sem sofrimento. Cinco serviços em produção dizem que funciona.

Padrão outbox transaccional é regra de ouro pra microsserviços que mantém consistência: salve evento na mesma transação do banco de dados, e um worker assíncrono publica isso pro broker. Garante exactly-once delivery na pratica (assumindo idempotência no consumer). A literatura desse padrão geralmente assume Kafka como destino e Debezium como CDC. Pra muitos times isso é overkill. NATS JetStream resolve com 1% da complexidade.

Implementação canônica em Camverly: cada serviço tem uma tabela outbox no seu schema com colunas (id, aggregate_id, type, payload, published_at). Toda mutação de domínio que importa publica um evento na outbox dentro da mesma transação que escreve em business tables. Isso é regra simples mas absoluta — nunca emita evento direto pro NATS de dentro do handler. Sempre via outbox.

Worker dedicado por serviço lê eventos com published_at IS NULL, publica no JetStream, marca como published. Esse worker é processo separado (cmd/worker no nosso layout) com retry exponencial em caso de falha de publicação. NATS JetStream garante persistência: uma vez ack recebido do server, evento está durável e consumers vão recebê-lo eventualmente. Pra latência tolerável (50-200ms entre commit e publicação), polling de 1 segundo funciona bem.

Vantagens em relação a CDC + Kafka: zero infraestrutura adicional (NATS já roda como broker primário pra outras coisas), latência mais baixa (sem etapa de log scrape), código mais simples (Go pure, sem Debezium config). Desvantagem: você precisa escrever o worker, e idempotência fica responsabilidade da aplicação. Pra times pequenos, esse trade é amplamente favorável. Pra times grandes com pipeline rico de transformação de evento, talvez não.

Detalhe de implementação que importa: outbox table cresce indefinidamente se você só marcar como published. Schedule diário de DELETE FROM outbox WHERE published_at < NOW() - INTERVAL '7 days'. Sete dias é suficiente pra investigar problemas de delivery e pra alguns retries longos; mais que isso é arquivo. Tabela outbox de um serviço típico em produção fica em 500MB constante, com I/O mínimo. Comparado ao custo cognitivo de Kafka, é troca evidente.

Nenhum comentário ainda

Seja o primeiro a comentar.

Deixe seu comentário

Entre com sua conta Canverly para comentar. Você pode usar a mesma conta em qualquer site da rede.

Entrar com Canverly