This project is sample of a Notification System built with Spring Boot (Java) and RabbitMQ, containing:
- User notifications (in-app, push mock)
- Broadcast messages
- News notifications with hash-based partitioning (preserves ordering per category)
- Dynamic listener registration (method 2) — one container per partition, registered programmatically
- Dead Letter Queues (DLQ) per partition
- Resilience4j: Circuit Breaker & Rate Limiter
- Log tracing entity (LogTrace) saved to DB
- SLF4J + custom logback-spring.xml using MDC keys: userId, notificationId
- H2 in-memory DB for quick testing
- Docker Compose to run RabbitMQ locally
See src/main/java/... for code. Key packages:
- config : RabbitMQ configuration and partition setup
- entity : Notification, UserPreference, LogTrace
- repository : Spring Data JPA repositories
- service : Publisher, Dynamic listener registrar, Notification service, Worker, Push sender
- controller : REST endpoints to send notifications and publish news
- Start RabbitMQ with Docker Compose: docker-compose up -d
- Build and run the Spring Boot app: mvn spring-boot:run
- Open RabbitMQ management UI: http://localhost:15672 (guest/guest)
- Use these endpoints:
- POST /api/notifications/send?userId=1&title=Hello&message=Hi
- POST /api/notifications/broadcast (body: JSON array of userIds, params title & message)
- POST /api/news/publish?categoryId=2&title=News&content=Hello
- GET /api/notifications/user/{userId} to query recent messages
- Partitioning / Ordering: Publisher calculates a partition based on categoryId % NUM_PARTITIONS and publishes to news.partition.{i} routing key.
- Dynamic listeners: DynamicNewsListenerRegistrar registers a SimpleMessageListenerContainer for each partition. Each container uses 1 consumer to preserve ordering inside that partition queue, while having multiple partitions allows parallelism.
- DLQ: Each partition queue is created with x-dead-letter-routing-key set to news.partition.{i}.dlq and those DLQ queues are also declared.
- Resilience4j: NotificationService uses @CircuitBreaker and @RateLimiter to protect DB and enqueue operations.
- Logging: Use MDC to inject userId and notificationId into logs. logback-spring.xml prints them.
- Trace logs: All important actions are saved to LogTrace table for audit.
- Designing a Notification System (DesignGurus): https://www.designgurus.io/course-play/grokking-system-design-interview-ii/doc/designing-a-notification-system , https://medium.com/@tanushree2102/designing-a-scalable-notification-system-from-hld-to-lld-e2ed4b3fb348
- RabbitMQ message ordering (Medium): https://medium.com/batc/rabbitmq-message-ordering-on-multiple-consumers-6f484858f589