A fault-tolerant event-driven notification platform built using Spring Boot microservices, Apache Kafka, Redis, and MySQL.
This project demonstrates how modern distributed backend systems achieve:
- asynchronous communication,
- reliable event publishing,
- retry handling,
- idempotency,
- eventual consistency,
- DLQ processing,
- and resilient microservice communication.
Microservices communicate asynchronously through Apache Kafka.
Prevents dual-write inconsistencies between database transactions and Kafka publishing.
Distributed services independently process events while eventually reaching consistent business state.
Prevents duplicate notification creation during retries or repeated client requests.
Protects APIs from abuse and excessive request bursts.
- Kafka publishing retries
- Email delivery retries
- Exponential backoff support
Unrecoverable failures are routed to dedicated Kafka DLQ topics for debugging and replay.
Handles:
- Kafka downtime
- Duplicate Kafka events
- SMTP failures
- Service crashes
- Retry exhaustion
- Temporary infrastructure failures
βββββββββββββββββββββββ
β Client/API β
ββββββββββββ¬βββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββ
β notification-service β
ββββββββββββββββββββββββββββββββββ
β β
β β
βΌ βΌ
notifications outbox_events
(MySQL) (MySQL)
β
βΌ
Outbox Scheduler
β
βΌ
Kafka Topic: notification-events-topic
β
βΌ
ββββββββββββββββββββββββββββββββββ
β email-service β
ββββββββββββββββββββββββββββββββββ
β β
β β
βΌ βΌ
sent_emails outbox_events
(MySQL) (MySQL)
β
βΌ
Email Retry Scheduler
β
βΌ
SMTP / Email Sender
β
βΌ
notification-status-topic
β
βΌ
notification-service
β
βΌ
notifications.status updated
Instead of directly publishing Kafka events after DB writes, events are first persisted inside an outbox_events table.
A scheduler later publishes those events reliably to Kafka.
This guarantees:
- no event loss,
- retry capability,
- eventual consistency,
- safe recovery from Kafka downtime.
The system separately retries:
Retries actual SMTP/email delivery failures.
Stored in:
sent_emails.retryCount
Retries failed Kafka publishing of outbox events.
Stored in:
outbox_events.retryCount
This separation models real production-grade distributed systems.
Duplicate API requests are prevented using Redis idempotency keys.
Idempotency-Key: abc-123
Repeated requests with same key:
- do not create duplicate notifications,
- do not create duplicate Kafka events.
Permanent failures are routed to:
email-dlq-topic
Used for:
- debugging,
- replay,
- operational monitoring.
Responsible for:
- receiving notification requests,
- saving notification records,
- handling idempotency,
- rate limiting,
- publishing Kafka notification events,
- consuming final email status updates.
| Component | Responsibility |
|---|---|
| NotificationController | REST API layer |
| NotificationService | Core business logic |
| IdempotencyService | Redis-based duplicate protection |
| RateLimiterService | Redis fixed-window rate limiting |
| OutboxScheduler | Reliable Kafka publishing |
| NotificationStatusConsumer | Consumes EMAIL_SENT / EMAIL_FAILED |
Responsible for:
- consuming notification events,
- sending emails asynchronously,
- retrying failed email deliveries,
- publishing final email delivery status,
- DLQ handling.
| Component | Responsibility |
|---|---|
| EmailNotificationConsumer | Kafka consumer |
| EmailService | Core email processing logic |
| EmailSenderService | SMTP/email sending |
| EmailRetryScheduler | Retries failed email sends |
| OutboxScheduler | Reliable Kafka publishing |
| DlqService | Handles unrecoverable failures |
| Topic | Purpose |
|---|---|
notification-events-topic |
Notification creation events |
notification-status-topic |
Final email delivery status |
email-dlq-topic |
Failed unrecoverable events |
Tracks business notification lifecycle.
| Status |
|---|
| PENDING |
| SENT |
| FAILED |
Tracks reliable Kafka event publishing.
| Status |
|---|
| PENDING |
| FAILED |
| PUBLISHED |
| DEAD_LETTERED |
Tracks actual email delivery lifecycle.
| Status |
|---|
| PROCESSING |
| RETRY_PENDING |
| SENT |
| FAILED |
Tracks reliable Kafka status event publishing.
Client Request
β notification-service
β Save Notification
β Save Outbox Event
β Kafka Publish
β email-service Consumes Event
β Email Sent Successfully
β Save EMAIL_SENT Outbox Event
β Kafka Publish
β notification-service Consumes EMAIL_SENT
β Notification marked SENT
Client Request
β Kafka Publish Success
β email-service Consumes Event
β SMTP Failure
β Retry Scheduled
β Retries Exhausted
β EMAIL_FAILED Outbox Event Created
β Kafka Publish
β notification-service Consumes EMAIL_FAILED
β Notification marked FAILED
β Failure Routed to DLQ
| Technology | Usage |
|---|---|
| Java 21 | Backend Language |
| Spring Boot | Microservices Framework |
| Spring Kafka | Kafka Integration |
| Spring Data JPA | ORM Layer |
| Apache Kafka | Event Streaming |
| Redis | Idempotency + Rate Limiting |
| MySQL | Persistent Storage |
| Docker Compose | Local Infrastructure |
| Lombok | Boilerplate Reduction |
| Maven | Dependency Management |
distributed-notification/
β
βββ common-events/
β
βββ notification-service/
β
βββ email-service/
β
βββ docker-compose.yml
β
βββ mysql-init/
docker compose up -dcd notification-service
mvn spring-boot:runcd email-service
mvn spring-boot:runPOST /api/v1/notificationsIdempotency-Key: abc-123
{
"recipient": "shivam@gmail.com",
"subject": "Welcome",
"message": "Welcome to NotifyX"
}- β Kafka broker downtime
- β Duplicate API requests
- β Duplicate Kafka delivery
- β Email service downtime
- β Kafka publish failures
- β SMTP failures
- β Retry exhaustion
- β Scheduler recovery
- β DLQ routing
- β Eventual consistency recovery
- Kubernetes Deployment
- API Gateway
- Authentication & Authorization
- Prometheus + Grafana Monitoring
- Distributed Tracing
- OpenTelemetry
- Email Templates
- Multi-channel Notifications (SMS/Push)
- Circuit Breakers
- Saga Pattern
Backend Engineer passionate about distributed systems, scalable backend architectures, and event-driven microservices.