How to design a notification delivery system

· Category: System Design

Short answer

A notification system routes messages to users through multiple channels such as push, email, and SMS with reliability and preference management.

Steps

  1. Accept notification requests with user ID, content, and priority.
  2. Resolve user preferences and active devices for channel selection.
  3. Enqueue notifications for asynchronous delivery.
  4. Attempt delivery through each channel with provider APIs.
  5. Track delivery status and retry failed attempts with backoff.

Tips

  • Respect user preferences and quiet hours to avoid fatigue.
  • Batch non-urgent notifications to reduce provider costs.
  • Use fallback channels when primary delivery fails.
  • Maintain templates and localization for consistent messaging.

Common issues

  • Provider rate limits throttling high-volume sends.
  • Outdated device tokens causing delivery failures.
  • Duplicate notifications from retries without deduplication.
  • Cross-channel preference synchronization gaps.

Example

# Consistent hashing for service discovery
import hashlib

def get_node(key, nodes):
    hash_val = int(hashlib.md5(key.encode()).hexdigest(), 16)
    return nodes[hash_val % len(nodes)]

node = get_node('user-123', ['node-a', 'node-b', 'node-c'])

This snippet implements consistent hashing to distribute keys across nodes, a foundational technique in scalable distributed systems.

Additional context

Applying these principles consistently across projects leads to more maintainable systems, clearer team communication, and better outcomes for end users. Regular review and refinement of practices ensure continuous improvement.