Pub/Sub
16 min
Pub/Sub decouples senders from receivers entirely: a publisher sends a message to a named CHANNEL, and every current subscriber to that channel receives it — the publisher never needs to know who (or how many) is listening.
class PubSub:
def __init__(self):
self.subscribers = {}
def subscribe(self, channel, callback):
self.subscribers.setdefault(channel, []).append(callback)
return self
This is exactly the Observer pattern from the Design Patterns course, generalized across multiple named channels instead of one fixed list of observers.
Two completely independent services react to the same event -- neither knows the other exists. Adding a THIRD subscriber later (fraud detection, say) needs zero changes to the code that publishes 'orders' events.
Unlike a message QUEUE (where one message goes to exactly ONE consumer, who then removes it), pub/sub is fan-out: every subscriber gets every message, and a subscriber that wasn't listening when a message was published simply never sees it — Redis pub/sub doesn't persist messages for later delivery. This makes it ideal for real-time notifications (chat, live updates, cache invalidation broadcasts) and a poor fit for anything that needs guaranteed delivery or replay (a proper message queue, or Kafka from later in the catalog, fits that need better).
def channel_subscriber_counts(subscriptions):
result = {}
for channel, sub_id in subscriptions:
result.setdefault(channel, set()).add(sub_id)
return {ch: len(subs) for ch, subs in result.items()}
Given `PubSub` below (with `subscribe` implemented), write `publish(self, channel, message)`: call every subscriber's callback (for that channel) with `message`, and return a list of their return values.
Write `channel_subscriber_counts(subscriptions)`: given a list of `(channel, subscriber_id)` pairs, return a dict mapping each channel to its count of DISTINCT subscribers.
What's the key characteristic of the pub-sub (publish-subscribe) pattern?
You can implement pub/sub fan-out to multiple subscribers per channel, and understand how it differs from a message queue (broadcast vs. single-consumer, no persistence for late subscribers).