40 min read Case Study Part 4 · Lesson 17 (17 / 18)
Course 11: Part 4 — Production Case Studies

Lesson 11.17 — Designing a Notification System: Multi-Channel, Priority Queues, Idempotency, and DLQs

Every major internet platform emits tens of millions of alerts daily—order confirmations, friend requests, two-factor OTPs, and price drop digests. How do you architect a resilient notification platform across Push, SMS, Email, and In-App channels without losing messages or double-charging users?

What You Will Master in This Lesson

Event-Driven Asynchronous Decoupling: Isolating upstream checkout and auth paths from telecom provider latency using Kafka/RabbitMQ brokers.
Priority Queues & Starvation Prevention: Guaranteeing that massive marketing blasts never delay critical 2FA OTP codes and security warnings.
Idempotency & Deduplication: Eliminating duplicate SMS/Email dispatch caused by transient network timeouts and unacknowledged retries.
Provider Fallbacks & Dead-Letter Queues (DLQ): Automated failover across telecom vendors and isolating poison-pill messages after retry exhaustion.

1. What is a Notification System and Why Does Every Architecture Need One?

So far, we have designed four monumental real-world architectures: a URL Shortener, a Real-Time Chat System, a Social Media Feed, and a Video Streaming Platform. Each system highlighted unique trade-offs in storage, real-time protocols, fan-out write amplification, and petabyte-scale CDN caching.

Yet behind almost every modern commercial application operates a critical shared utility service: the Notification System.

Consider an e-commerce checkout flow: you click “Place Order”. Within seconds, a push notification illuminates your smartphone: “Order #5021 Placed!”. Simultaneously, an order summary lands in your email inbox, and an SMS arrives with a courier delivery pin. If a friend messages you, you get notified. If a fraudulent login attempt occurs from an unrecognized IP, an urgent two-factor OTP alert is dispatched instantly.

A Notification System is a centralized, distributed messaging pipeline that consumes business events from upstream domain services, evaluates user delivery preferences, renders localized templates, and reliably dispatches messages across multiple external telecommunication and push channels.

2. Functional and Non-Functional Requirements

Functional Requirements

  • Event Ingestion: Ingest domain events seamlessly from upstream microservices (Order, Payment, Auth, Social).
  • Multi-Channel Dispatch: Support Mobile Push (iOS APNs, Android FCM), SMS (Twilio, Infobip), Email (AWS SES, SendGrid), and In-App Notification Center.
  • Dynamic Templating & Localization: Inject event parameters into localized multi-language templates.
  • User Preference Filtering: Respect opt-in and opt-out settings per channel and category (e.g. promotional emails disabled, security alerts strictly enforced).
  • Scheduled Notifications: Allow scheduling messages for future dispatch (e.g. reminders at 9:00 AM tomorrow).
  • Delivery Status Tracking: Track full notification lifecycle state (queued, sent, delivered, failed).

Non-Functional Requirements

  • Massive Scalability: Handle 50+ Million daily notifications and withstand peak ingestion surges of 10,000+ events/second.
  • Zero Silent Loss (Reliability): Transactional receipts and critical alerts must never be lost in transit.
  • Sub-Second Latency for High-Priority Alerts: Two-factor auth codes and fraud warnings must reach the user within 2-3 seconds.
  • Fault Tolerance & Provider Isolation: Outages in external telecom providers (e.g., Twilio downtime) must never cascade into push or email delivery failures.
  • Strict Idempotency: Network timeouts and worker retries must never trigger duplicate SMS or charge deductions.

3. Why Notification Delivery Must Be 100% Asynchronous

Suppose a customer submits an order. The primary responsibility of the Order Service is transactional:

[ Client ] ──POST /order──► [ Order Service ] ──DB Commit──► [ 201 Created Response ]

If the Order Service synchronously connects to SendGrid for an email and Twilio for an SMS within the same HTTP thread, the user’s browser will be locked behind a 3-second spinner. Worse, if SendGrid experiences latency or a network timeout, the user’s entire purchase could fail!

The Solution: Decoupled Event-Driven Ingestion.

Order Service ──► DB Commit ──► Publish Event (Kafka) ──► Immediate HTTP 201 Response
                                                             │
                                                            ▼
                                            [ Asynchronous Workers Drain Messages ]

The customer receives a sub-100ms response. In the background, distributed notification workers independently format, throttle, and deliver the messages.

4. Template Engines and User Preference Filtering

Even when dispatching hundreds of millions of notifications, message formats are standardized. Hardcoding strings inside microservice code is an anti-pattern; instead, architectures employ a centralized Template Engine.

Incoming Event Payload (JSON):
{
  "event": "ORDER_SHIPPED",
  "order_id": 5021,
  "user_id": 10045,
  "carrier": "FedEx",
  "tracking_no": "TRK-8890"
}
Rendered Message (Localized):

EN: Your order #5021 has been shipped via FedEx. Tracking: TRK-8890.

BN: আপনার অর্ডার #5021 পাঠানো হয়েছে। ট্র্যাকিং কোড: TRK-8890।

User Preferences Filter

Not every user wishes to receive marketing broadcasts on every channel. Prior to queueing a notification, the ingestion service queries an in-memory Redis cache for the user’s notification preferences:

Push Alerts: ON
Security OTP: ON
Marketing Email: OFF
Promotional SMS: OFF

5. Priority Queues & Starvation Prevention

Notifications have wildly different business urgencies:

1. High Priority (Critical) Password reset OTPs, two-factor authentication tokens, debit fraud alerts. (Latency SLA: < 2 seconds).
2. Normal Priority Order shipping updates, friend requests, social mentions. (Latency SLA: < 1 minute).
3. Low / Bulk Priority Weekly marketing digests, re-engagement newsletters, coupon blasts. (Latency SLA: < 2-4 hours).
The Peril of Queue Starvation If all messages are pushed into a single shared FIFO queue, a marketing campaign pushing 1,000,000 promotional emails at 2:00 PM will completely choke the pipeline. If a user requests a 2FA OTP at 2:01 PM, their security token will be stuck behind 1 million marketing emails, causing the user to wait 20 minutes for a login code!

Architectural Solution: Segregate traffic into dedicated Priority Queues (High, Normal, Bulk) backed by weighted dequeuing or dedicated high-priority worker fleets.

6. Channel Workers & 3rd-Party Telecom Integration

A notification platform must never attempt to build its own cellular base stations or global SMTP relays. Instead, channel-specific worker fleets integrate with enterprise third-party providers:

Channel Industry Standard Providers Typical Provider Latency Cost & Throttling Profile
Mobile Push Apple APNs, Google FCM 50 - 200 ms Free (High Throughput)
Email AWS SES, SendGrid, Mailgun 200 - 500 ms Very Low (~$0.10 / 1,000 emails)
SMS Twilio, Infobip, Sinch 1 - 4 seconds Expensive ($0.015 - $0.05 / SMS)
In-App Center Internal DB + WebSockets < 10 ms Internal database storage cost only

7. Idempotency & The Threat of Double Delivery

In distributed networks, the most dangerous failure mode is the Two-Phase Acknowledgment Drop:

1. Worker sends API request to Twilio: "Send OTP to +1-415-555-0199"
2. Twilio successfully transmits the SMS to the cellular network.
3. A transient router glitch severs the return connection before the worker receives HTTP 200 OK.
4. The worker experiences a network timeout, assumes delivery failed, and retries the job.
5. Twilio receives the second request and sends a duplicate SMS to the user’s phone!

Architectural Mitigation: Idempotency Keys

  • Every notification event carries a deterministic event_id and a client-generated Idempotency-Key.
  • When invoking vendor APIs (e.g. Twilio, Stripe), the worker passes this key in the HTTP request headers. The vendor caches the key for 24 hours, returning the cached response for duplicates without re-transmitting.
  • At the worker level, an atomic Redis lock (SET notification_id "PROCESSING" NX EX 300) prevents concurrent worker threads from processing the same event.

8. Delivery Semantics: Sent vs. Delivered

Status: “SENT”

The internal notification service has successfully submitted the payload to the external provider (SendGrid, Twilio), and the vendor acknowledged HTTP 200. This does not mean the user received it!

Status: “DELIVERED”

The upstream vendor confirmed downstream handshake with the recipient’s cellular carrier or mail server, and asynchronously notified our platform via an incoming Webhook Callback.

9. Provider Fallbacks, Retries, and Dead-Letter Queues (DLQ)

Vendors experience outages. How does a production system maintain resilient delivery?

1. Multi-Provider Fallback Routing: If Twilio returns consecutive 5xx errors, workers automatically switch the active routing table to a secondary gateway (e.g. Infobip or Sinch).
2. Exponential Backoff with Jitter: Instead of hammering a degraded service, workers retry with increasing time deltas (1s, 4s, 16s) plus randomized jitter to prevent thundering herd stampedes.
3. Dead-Letter Queues (DLQ): If a message fails repeatedly after 5 attempts (e.g. due to an invalid phone number format), it is isolated in a Dead-Letter Queue. This unblocks the queue while preserving the failed message for engineer inspection.

10. The Master Architecture Blueprint

Connecting all the architectural components into a complete end-to-end distributed system:

UPSTREAM APPLICATION SERVICES [ Order ] [ Auth/OTP ] [ Payment ] [ Social ] │ │ │ │ └─────────────┼───────────────┴──────────────┘ │ (Async Business Events) ▼ [ Kafka Event Bus ] │ ▼ [ Notification Ingestion API ] │ ┌────────────┴────────────┐ ▼ ▼ [ User Preferences Cache ] [ Template Engine ] │ │ └────────────┬────────────┘ │ (Validated & Priority Tagged) ▼ [ Priority Routing Queue ] ┌────────────────┼────────────────┐ ▼ ▼ ▼ [ High (OTP) ] [ Normal (Orders) ] [ Bulk (Promo) ] │ │ │ └────────────────┼────────────────┘ │ ┌───────────────────┼───────────────────┐ ▼ ▼ ▼ [ Push Worker Fleet ] [ Email Worker Fleet ] [ SMS Worker Fleet ] │ │ │ (APNs / FCM) (SES / SendGrid) (Twilio / Infobip) │ │ │ └───────────────────┼───────────────────┘ │ ▼ (Webhook Receipts) [ Delivery Status Service ] │ ┌────────────────┴────────────────┐ ▼ ▼ [ PostgreSQL Store ] [ Dead-Letter Queue (DLQ) ] (In-App Notification DB) (Failed Poison Messages)
Interactive Studio

Notification Architecture Workbench

Multi-channel priority dispatcher, delivery state machine, and telecom cost calculator.

Concept Verification

Notification Architecture Quiz

Test your understanding of distributed messaging and real-world failure handling.

1. A worker invokes Twilio’s API to dispatch an SMS. Twilio sends the SMS to the recipient’s phone, but a network disconnect drops the HTTP response before the worker can receive confirmation. What architectural mechanism prevents double SMS delivery upon retry?

2. At 2:00 PM, a marketing campaign pushes 500,000 promotional emails into the system. Simultaneously, a customer requests a login OTP code. How does a well-designed architecture guarantee that the OTP is delivered within 2 seconds?

3. A notification dashboard displays an alert with the status “SENT”. What does this status indicate technically?

Next Lesson · Part 4 · Lesson 18

Designing a Scalable Authentication System: How Millions of Users Login Securely

When hundreds of millions of concurrent users authenticate simultaneously, how do you handle password hashing algorithms, distributed session state, JWT refresh token rotation, OAuth2/SSO federations, and brute-force rate limiting?