System design · LLD design

Notification System

FR

1.Send a notification to a user through one or more channels - email, sms , push.
2.User have pre channel contact info & can have preferred channels
3.Notification have 2 priority levels : HIGH and NORMAL and if there is a backlog HIGH to push forward
4.High priority notifications should bypass the user preferred channels only if have a valid user contact info
5.Failed notification per channel should have a 3 attempts retry , and then marked failed if still not worked
6.Cap notification per user within a time window , but still process the priority one and skip the other notification in that window
7.Tracking notification for analytic/logging purpose

NFR

1.Scalable: system should be able to handle increase number of notifications
2.Extensible: system should be able to swap the priority logic
3.Reliability : channel failure should be isolated from each other
4.Concurrency: handle concurrent notification for a user in rate limiter counter
5. Idempotency: Safe retry for failed notifications
6.Adding different tracking notification should not affect the dispatch flow

Entities and classes

Channel enum
EMAIL , SMS , PUSH

User
-userID
-Map<Channel, string> contactInfo
-preferredchannels :Set<Channels>

getContactInfo(channel) : optional<String>

Priority enum
HIGH , NORMAL

NotificationStatus - enum
PENDING , SENT , FAILED

Notification

-notificationid
-userID
-title

-message
-priority

DeliverResult
-notificationID
-userID
-channel
-status
-attemptCount
-timestamp

NotificationChannelFactory - factory

-mapChannels <Channel, NotificationChannel> which will create a new RetryNotificationChannel
+getNotificationChannel(channel)

NotificationChannel - interface
+send(contactInfo , message) : boolean

EMAILChannel - implements NotificationChannel
+send(contactInfo , message) : boolean

SMSChannel - implements NotificationChannel
+send(contactInfo , message) : boolean

RetryNotificationChannel - implements NotificationChannel - the decorator

-attempCount;

+send(contactInfo , message) : boolean 3 time retry if pass return true else false
+getAttemptCount()

NotificationObserver - interface
+onResult(DeliverResult result)

NotificationService
-factory NotificationChannelFactory
-List<NotificationObserver> observers
RateLimiter ratelimiter

+notificationDispatcher(notification, user )
exceedlimit(userid) ? return
getContactInfo()

   {
   // find the notificationchannel from factory
   // send
   // record - success ? then SENT : FAILED
   // add to observer
    }

+priorirtiseListOfNotification(List<Notification> notification )
Use priority queue (PriorityBlockingQueue) for publishing first notification for high priority