Notifications: From Event to Channel
The high-level design is the map of parts that carries an event from the app to the user's channel. This lesson builds that map, the high-level design step of the interview method.
Events wait in a queue
Events land in a queue and a worker takes them in arrival order. The printout shows the order the worker receives.
queue = []
queue.append("event 1: a like")
queue.append("event 2: a comment")
queue.append("event 3: a password change")
while queue:
event = queue.pop(0)
print("worker takes", event)
print("queue holds", len(queue), "events")One worker per channel
Each notification names its channel, and the matching worker sends it. The counts show how the five notifications spread across the workers.
notifications = [
("n1", "push"),
("n2", "email"),
("n3", "push"),
("n4", "text message"),
("n5", "push"),
]
workers = {"push": 0, "email": 0, "text message": 0}
for note_id, channel in notifications:
workers[channel] += 1
print(note_id, "goes to the", channel, "worker")
for channel in ["push", "email", "text message"]:
print(channel, "worker sent", workers[channel])The notification record
One notification is stored as a small record of plain fields. The record carries everything a channel worker needs to send.
record = {
"event id": "like-41",
"user": "Ana",
"channel": "push",
"text": "Ben liked your photo",
}
for field in ["event id", "user", "channel", "text"]:
print(field, ":", record[field])Example
event = {"id": "like-41", "kind": "like", "text": "Ben liked your photo"}
preferences = {
"Ana": {"push": True, "email": True},
"Ben": {"push": False, "email": True},
}
print("event", event["id"], "lands on the notifications topic")
for user in ["Ana", "Ben"]:
prefs = preferences[user]
if prefs["push"]:
channel = "push"
elif prefs["email"]:
channel = "email"
else:
channel = "none"
print("preferences checked for", user, "->", channel, "worker sends:", event["text"])Key points
- Pub-sub topic: the named stream where a new event lands for workers to pick up.
- Queue: events wait in a queue, so a burst of events does not crush the senders.
- Channel worker: a worker program that sends on one channel only, like the push worker.
- Preference check: the step that reads a user's preferences before any send happens.
- Notification record: the stored facts of one notification, holding the event id, the user, the channel and the text.
In this example, one like event lands on the topic and the preference check routes it for two users. Ana's push preference sends it to the push worker, and Ben's switched-off push sends it to the email worker instead.
Note
the preference check sits before the channel workers, so an opted-out user is never sent to.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
Where does the preference check belong in the design?