List functional requirements for the system (Ask the chat bot for hints if stuck.)...
List non-functional requirements for the system...
Estimate the scale of the system you are going to design...
Define what APIs are expected from the system...
POST /sms/send
POST /email/send
POST /notification/user_preference
request body
{
notification_type: "email",
service_type: "comments"
}
Request body
{
"to":[
{
"user_id":123456
}
],
"from":{
"email":"[email protected]"
},
"subject":"Hello World!",
"content":[
{
"type":"text/plain",
"value":"Hello, World!"
}
]
}
Defining the system data model early on will clarify how data will flow among different components of the system. Also you could draw an ER diagram using the diagramming tool to enhance your design...
user
user_id
name
device_id: []
device:
device_id
device_token
user_id
last_loggedin
for this one we want to have strong consistency so use relational database.
user_preference
user_id
service_type
opt-in (boolean)
You should identify enough components that are needed to solve the actual problem from end to end. Also remember to draw a block diagram using the diagramming tool to augment your design. If you are unfamiliar with the tool, you can simply describe your design to the chat bot and ask it to generate a starter diagram for you to modify...
Notification servers: They provide the following functionalities:
Provide APIs for services to send notifications. Those APIs are only accessible internally or by verified clients to prevent spams.
Carry out basic validations to verify emails, phone numbers, etc.
Query the database or cache to fetch data needed to render a notification.
Put notification data to message queues for parallel processing.
Cache: User info, device info, notification templates are cached.
DB: It stores data about user, notification, settings, etc.
Message queues: They remove dependencies between components. Message queues serve as buffers when high volumes of notifications are to be sent out. Each notification type is assigned with a distinct message queue so an outage in one third-party service will not affect other notification types.
Workers: Workers are a list of servers that pull notification events from message queues and send them to the corresponding third-party services.
Explain how the request flows from end to end in your high level design. Also you could draw a sequence diagram using the diagramming tool to enhance your explanation...
1. A service calls APIs provided by notification servers to send notifications.
2. Notification servers fetch metadata such as user info, device token, and notification setting from the cache or database.
3. A notification event is sent to the corresponding queue for processing. For instance, an iOS push notification event is sent to the iOS PN queue.
4. Workers pull notification events from message queues.
5. Workers send notifications to third party services.
6. Third-party services send notifications to user devices.
Dig deeper into 2-3 components and explain in detail how they work. For example, how well does each component scale? Any relevant algorithm or data structure you like to use for a component? Also you could draw a diagram using the diagramming tool to enhance your design...
Explain any trade offs you have made and why you made certain tech choices...
Fanout service:
in-memory message queue vs log based message broker:
in-memory message broker: have a bunch tasks that you don't care about the order, or replaying them if something's broken downstream
log based message broker: can easily replay messages because they are stored on disk
how to ensure messages are delivered once?
idempotency key, if we have seen it before, discard it, otherwise we can send out notifications. Idempotency key can be stored in memory at the consumer level.
Try to discuss as many failure scenarios/bottlenecks as possible.
If a server is offline, save the failed notifications in a secondary database. This database will be column based like HBase.
What are some future improvements you would make? How would you mitigate the failure scenario(s) you described above?
Modify you system to support buffering notification delivery on a time intervals basis.
Plugin Architecture. Implement a plugin-based architecture where different notification types can be developed and added as separate modules. Each team can create their custom notification type without impacting the core notification service.
Monitor queued notifications
A key metric to monitor is the total number of queued notifications. If the number is large, the notification events are not processed fast enough by workers. To avoid delay in the notification delivery, more workers are needed.