“Every event is an opportunity to surprise the user — or to flood them with noise.” — #30DiasJava Logbook
🎯 Objetivo do Day 5
O quinto dia do #30DiasJava inaugurou o lado em tempo real da plataforma. A missão: construir um Notification Service capaz de tratar eventos de domínio, entregar mensagens em múltiplos canais e manter governança mesmo antes de subir para Kafka ou RabbitMQ.
🛠️ Destaques da implementação
- Orquestração por eventos:
NotificationRequestedEventdesacopla produtores dos canais (email, push, in-app). Cada listener roda de forma assíncrona com@EventListener+@Async. - Outbox + idempotência: registros pendentes vão para
notification_outboxe só são marcados comoDELIVEREDquando o canal confirma. Duplicatas são bloqueadas com índices únicos. - WebSockets vs SSE: o serviço expõe ambos. SSE para streams leves e estáveis; WebSockets para experiências interativas. Em ambos, JWT + rate limiting em Redis.
- Roteamento inteligente: regras de prioridade por público, janelas de silêncio e preferências por canal.
- Observabilidade: métricas (
notification_delivery_seconds,notification_retry_total), logs comtraceId/recipientIde dashboards com heatmaps de erro.
💡 Lições do dia
- Dá para começar “pequeno” com Spring Events sem fechar a porta para brokers mais robustos — basta modelar tudo como mensagens imutáveis.
- Idempotência precisa ser tratada desde o primeiro webhook, mesmo que o tráfego ainda seja baixo.
- Métricas e tracing são tão importantes quanto o payload: sem visibilidade, é impossível saber se os usuários estão recebendo as mensagens certas.
🔗 Recursos
- Artigo completo: https://enouveau.io/blog/2025/11/05/notification-service-event-driven.html
- Repositório: https://github.com/adelmonsouza/30DiasJava-Day04-NotificationService
- Projeto pessoal: Este é um projeto do desafio #30DiasJava, mantido independentemente para fins educacionais.
Next episode → Day 6/30 — Docker Professional Stack in 7 Steps