WEBSOCKETREDIS
REAL-TIME COMMUNICATION
WebSocket patterns, event-driven architectures, and scaling real-time features.
WebSocket vs SSE vs Polling
WebSocket: bidirectional, persistent — use for chat, collaborative editing. SSE: server-to-client only — use for notifications. For the community forum, WebSocket was the clear choice.
WebSocket Hub Pattern in Go
A central hub manages all connections, rooms, and message broadcasting. Each connection runs in its own goroutine with channels for communication.
go
type Hub struct {
rooms map[string]map[*Client]bool // roomID -> clients
broadcast chan *Message
register chan *Client
unregister chan *Client
mu sync.RWMutex
}
func (h *Hub) Run() {
for {
select {
case client := <-h.register:
h.mu.Lock()
if _, ok := h.rooms[client.RoomID]; !ok {
h.rooms[client.RoomID] = make(map[*Client]bool)
}
h.rooms[client.RoomID][client] = true
h.mu.Unlock()
case client := <-h.unregister:
h.mu.Lock()
if clients, ok := h.rooms[client.RoomID]; ok {
delete(clients, client)
close(client.Send)
if len(clients) == 0 { delete(h.rooms, client.RoomID) }
}
h.mu.Unlock()
case msg := <-h.broadcast:
h.mu.RLock()
if clients, ok := h.rooms[msg.RoomID]; ok {
for client := range clients {
select {
case client.Send <- msg.Data:
default:
close(client.Send)
delete(clients, client)
}
}
}
h.mu.RUnlock()
}
}
}Scaling with Redis Pub/Sub
Single-server WebSocket breaks at scale. Redis Pub/Sub bridges multiple instances — publish on one server, all servers receive and broadcast to their connected clients.
go
// Subscribe to Redis and broadcast to local WebSocket clients
func (h *Hub) SubscribeToRedis(rdb *redis.Client) {
pubsub := rdb.Subscribe(ctx, "chat:*")
ch := pubsub.Channel()
for msg := range ch {
// msg.Channel = "chat:room123"
roomID := strings.TrimPrefix(msg.Channel, "chat:")
h.broadcast <- &Message{
RoomID: roomID,
Data: []byte(msg.Payload),
}
}
}
// Publish message — goes to all server instances
func (h *Hub) PublishMessage(rdb *redis.Client, roomID string, data []byte) {
rdb.Publish(ctx, "chat:"+roomID, data)
}