The pattern "Hub" in Golang
In the Go ecosystem, the hub pattern is a standard architecture for managing many-to-many communications, such as WebSocket servers, chat rooms, or real-time notification systems.
It centralizes state management into a single Hub structure, using channels to synchronize data instead of complex (and often buggy) mutex locking across multiple goroutines.
The core philosophy
The mantra “Don’t communicate by sharing memory; share memory by communicating” means that instead of having 100 goroutines trying to read and write to the same map of “connected users” simultaneously (which requires heavy locking), you give that map to one manager (the hub).
If a goroutine wants to change something, it sends a message to the hub via a channel.
Example with the mutex approach
With a sync.Mutex, you allow multiple goroutines to access the same struct, but you lock the access so they don’t step on each other.
The vibe: a shared notebook where everyone has to wait in line to grab the pen.
type SafeCounter struct { sync.Mutex Value int}
func (c *SafeCounter) Increment() { c.Lock() // Manually locking c.Value++ c.Unlock() // Manually unlocking}- Manual locking often leads to maintenance overhead as features grow
- Failure to manage lock lifecycle creates high risks for race conditions and deadlocks
- Heavy use can lead to lock contention, significantly bottlenecking high-concurrency throughput
Example with the hub pattern
In the hub pattern, the data lives inside a single “manager” goroutine. If other goroutines want to change the data, they send a message to the hub.
The vibe: a clerk behind a desk. you don’t touch the files; you hand the clerk a request, and they update the files for you.
The state is “hidden” inside a run() loop. There are no locks because only one goroutine ever touches the users map.
type Hub struct { users map[string]bool register chan string}
func (h *Hub) Run() { for { select { case name := <-h.register: // No Mutex needed! // This line is thread-safe because only this loop runs it. h.users[name] = true } }}The anatomy of a hub
A typical hub implementation consists of three main components:
- The hub struct: it keeps track of active connections and processes requests to register, unregister, or broadcast.
type Hub struct { // Registered clients. clients map[*Client]bool // Inbound messages from the clients. broadcast chan []byte // Register requests from the clients. register chan *Client // Unregister requests from clients. unregister chan *Client}- The client: it usually contains the connection object and a buffered channel for outbound messages.
type Client struct { hub *Hub conn *websocket.Conn // We can imagine a websocket connection here send chan []byte}- The Run loop: it runs a single select statement inside a for loop (usually in its own goroutine). this ensures that only one operation happens at a time, effectively making the code thread-safe without manual sync.
func (h *Hub) Run() { for { select { case client := <-h.register: h.clients[client] = true case client := <-h.unregister: if _, ok := h.clients[client]; ok { delete(h.clients, client) close(client.send) } case message := <-h.broadcast: for client := range h.clients { select { case client.send <- message: default: close(client.send) delete(h.clients, client) } } } }}You may find a full example here : https://github.com/gorilla/websocket/tree/main/examples/chat
When to use it
- You want to manage thousands of concurrent connections like WebSockets.
- You want to broadcast events to multiple subscribers for pub/sub systems.
- You want to synchronize state updates to all players in a room in a game server.
Which one should you use?
- Use a mutex when you have a simple data structure (like a counter or a cache) where the logic is just “Read/Write.
- Use a hub when you are coordinating complex events, like a WebSocket server, a game engine state, or a long-running background worker that needs to react to different types of commands.
Design pattern "Strategy"
Let's learn what is the "Strategy" design pattern
Design pattern "Visitor"
Let's learn what is the "Visitor" design pattern 🤝👋🚶🧳
Design pattern "Iterator"
Let's learn what is the "Iterator" design pattern 🔄
Design pattern "Observer"
Let's learn what is the "Observer" design pattern 💃👀👀👀
Design pattern "Memento"
Let's learn what is the "Memento" design pattern 📸️🖼️🖼️🔄🕰️🔍
Design pattern "Facade"
Let's learn what is the "Facade" design pattern 🕹️🏎️💨
Design pattern "Decorator"
Let's learn what is the "Decorator" design pattern 🪆☕☕☕
Design pattern "Composite"
Let's learn what is the "Composite" design pattern 🌳🌿🌿