The Publish/Subscribe (Pub/Sub) Pattern is a messaging paradigm where publishers send messages without knowing who will receive them, and subscribers receive messages without knowing who sent them. This decouples the producers and consumers of information, making the system more modular and scalable.
- Publisher: The entity that produces messages.
- Subscriber: The entity that consumes messages.
- Broker: The intermediary that facilitates communication between publishers and subscribers (can be implemented as a channel in Go).
- Publish Messages: Publishers send messages to a centralized message broker (or directly to subscribers).
- Subscribe to Topics: Subscribers express interest in specific topics or message types.
- Distribute Messages: The broker delivers messages to all subscribers interested in a topic.
Implementing a Pub/Sub system using Go channels.
package main
import (
"fmt"
"sync"
"time"
)
type Broker struct {
mu sync.Mutex
subscribers map[string][]chan string
}
// Create a new Broker
func NewBroker() *Broker {
return &Broker{
subscribers: make(map[string][]chan string),
}
}
// Subscribe to a topic
func (b *Broker) Subscribe(topic string) <-chan string {
b.mu.Lock()
defer b.mu.Unlock()
ch := make(chan string, 1)
b.subscribers[topic] = append(b.subscribers[topic], ch)
return ch
}
// Publish a message to a topic
func (b *Broker) Publish(topic, message string) {
b.mu.Lock()
defer b.mu.Unlock()
for _, subscriber := range b.subscribers[topic] {
subscriber <- message
}
}
// Close all subscriber channels
func (b *Broker) Close() {
b.mu.Lock()
defer b.mu.Unlock()
for _, subscribers := range b.subscribers {
for _, subscriber := range subscribers {
close(subscriber)
}
}
}
func main() {
broker := NewBroker()
defer broker.Close()
// Subscribers
sub1 := broker.Subscribe("news")
sub2 := broker.Subscribe("news")
// Publisher
go func() {
for i := 1; i <= 3; i++ {
msg := fmt.Sprintf("Breaking News %d", i)
broker.Publish("news", msg)
time.Sleep(1 * time.Second)
}
}()
// Subscribers receive messages
wg := sync.WaitGroup{}
wg.Add(2)
go func() {
defer wg.Done()
for msg := range sub1 {
fmt.Println("Subscriber 1 received:", msg)
}
}()
go func() {
defer wg.Done()
for msg := range sub2 {
fmt.Println("Subscriber 2 received:", msg)
}
}()
wg.Wait()
}
- Broker:
- Manages topics and their subscribers.
- Synchronizes access to its internal state with a
sync.Mutex
.
Subscribe
:- Creates a channel for a new subscriber and associates it with the topic.
Publish
:- Sends messages to all channels subscribed to a specific topic.
- Concurrency:
- Uses goroutines for asynchronous message publishing and receiving.
The Pub/Sub Pattern enhances modularity and scalability by decoupling message producers and consumers. It's widely used in event-driven systems and real-time applications like chat apps, notifications, and logging systems.