[{"data":1,"prerenderedAt":40},["ShallowReactive",2],{"profile-pt-BR":3,"article-outbox-pattern-na-pratica-pt-BR":27},{"brandName":4,"fullName":5,"headline":6,"manifesto":7,"contactIntro":11,"avatar":12,"manifestoImage":13,"social":14},"Danilo Fernando","Danilo Fernando - Engenheiro de Software","Software bem construído, integrações confiáveis e arquitetura pensada para durar.",[8,9,10],"Minha jornada é guiada pela crença de que código é apenas uma ferramenta para resolver problemas de negócio complexos. Com sólida experiência em ecossistemas Java e Spring, dedico meus esforços a sistemas que não apenas funcionam, mas que são fáceis de manter e evoluir.","Especialista em APIs robustas e integrações críticas, acredito que maturidade técnica se reflete na capacidade de tomar decisões ponderadas, equilibrando inovação com as necessidades reais da organização.","Busco impacto real: Clean Code não é estética, é necessidade econômica para garantir a sustentabilidade do produto a longo prazo.","Estou sempre aberto a novas oportunidades profissionais, troca de experiências técnicas ou discussões sobre arquitetura e desenvolvimento de software.","\u002Fimages\u002Fprofile\u002Fdanilo.webp","\u002Fimages\u002Fprofile\u002Fdanilo_manifesto.webp",[15,19,23],{"kind":16,"label":17,"href":18},"email","E-mail","mailto:danilo.bossanova@hotmail.com",{"kind":20,"label":21,"href":22},"linkedin","LinkedIn","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fdanilo-fernando-dev\u002F",{"kind":24,"label":25,"href":26},"github","GitHub","https:\u002F\u002Fgithub.com\u002Fdanilobossanova",{"slug":28,"title":29,"excerpt":30,"category":31,"tags":32,"readTimeMinutes":36,"publishedAt":37,"author":4,"coverImage":38,"body":39},"outbox-pattern-na-pratica","Outbox pattern na prática com Spring Boot","Como garantir entregas at-least-once sem depender de transações distribuídas.","Arquitetura",[33,34,35],"eventos","spring-boot","kafka",9,"2025-03-01","https:\u002F\u002Fpicsum.photos\u002Fseed\u002Foutbox\u002F1200\u002F600","## O problema\n\nPublicar eventos de forma confiável junto de uma transação de banco é uma das\narmadilhas clássicas de sistemas distribuídos. Se você grava no Postgres e\ndepois publica no Kafka:\n\n```java\n@Transactional\npublic void confirm(Order order) {\n    orderRepository.save(order);       \u002F\u002F ✅ transação do banco\n    kafkaTemplate.send(\"orders\", order); \u002F\u002F ❌ fora da transação\n}\n```\n\nBasta um crash entre as duas chamadas para o banco dizer *\"confirmado\"* e o\nmundo nunca saber.\n\n## Outbox pattern\n\nA ideia é gravar o evento na **mesma transação** do banco, em uma tabela\n`outbox`. Um relay lê a tabela e publica de fato.\n\n### Schema mínimo\n\n```sql\nCREATE TABLE outbox (\n    id           UUID PRIMARY KEY,\n    aggregate    VARCHAR(64)  NOT NULL,\n    event_type   VARCHAR(128) NOT NULL,\n    payload      JSONB        NOT NULL,\n    created_at   TIMESTAMPTZ  NOT NULL DEFAULT now(),\n    published_at TIMESTAMPTZ\n);\nCREATE INDEX outbox_unpublished_idx\n    ON outbox (created_at) WHERE published_at IS NULL;\n```\n\n### Relay\n\nUm job simples lê eventos não publicados, envia ao broker e marca como\npublicado. O importante é:\n\n1. **Idempotência do consumidor** — o relay vai republicar em caso de falha.\n2. **Monitoramento do lag** — alerta se `outbox` crescer mais rápido que\n   consumir.\n3. **Batch controlado** — não trave o DB puxando 10k de uma vez.\n\n### Gotchas\n\n- Nunca dependa de ordem estrita do broker; use `aggregate_id` no particionamento.\n- Não faça *dead-letter* dentro da mesma tabela — crie `outbox_failed`.\n- Sempre grave o schema version do payload.\n\n## Quando evitar\n\nSe o seu sistema não precisa de garantia at-least-once, o outbox é overkill.\nUm `@TransactionalEventListener` do Spring resolve 80% dos casos.",1776457051526]