WebSocket & realtime coordination
WebSocket servers maintain persistent connections with clients. When you scale to multiple backend nodes, a message intended for a specific user may arrive at a node that does not hold that user’s WebSocket connection. tinybroker lets any node publish an event and every node that holds a relevant connection forward it — no sticky sessions required.
Architecture
Client A ── WS ── Node 1 ──┐
Client B ── WS ── Node 1 ──┤ ┌── Node 1 (forwards to A, B)
Client C ── WS ── Node 2 ──┤── Publish ─► TB ──┤
Client D ── WS ── Node 2 ──┤ └── Node 2 (forwards to C, D)
Client E ── WS ── Node 3 ──┘ Node 3 (no match, drops)
TB = tinybroker. Each node subscribes to the full event stream. Each node forwards only the events relevant to its connected clients.
Per-user topics
Use a per-user topic so nodes can filter efficiently at the broker level rather than fan-out everything and filter locally:
topic: "user.{user_id}.notify"
Node 1 subscribes to user.abc.notify when user abc connects, removes the pattern when they disconnect. Only Node 1 receives messages for user abc.
// When client connects
stream.Send(&pb.SubscribeCommand{
Command: &pb.SubscribeCommand_AddPatterns{
AddPatterns: &pb.AddTopicPatterns{
TopicPatterns: []string{"user." + userID + ".notify"},
},
},
})
// When client disconnects — remove the pattern to stop delivery
stream.Send(&pb.SubscribeCommand{
Command: &pb.SubscribeCommand_RemovePatterns{
RemovePatterns: &pb.RemoveTopicPatterns{
TopicPatterns: []string{"user." + userID + ".notify"},
},
},
})
Room / channel topics
For chat rooms or collaborative spaces, use room-scoped topics:
"room.{room_id}.message"
"room.{room_id}.presence"
Every node that has at least one connection in a room subscribes to room.{room_id}.*. When a user sends a message, any node publishes it; all nodes with room members receive and forward it.
Broadcast to all connected clients
Use a single wildcard pattern per node:
OpenSubscription { topic_patterns: ["notify.*"] }
Publish notify.maintenance and every connected client receives the alert via their node’s WebSocket.
Presence and typing indicators
For high-frequency events like typing indicators, consider filtering at the subscriber:
topic: "room.{room_id}.typing"
Nodes subscribe at the room level. The handler checks whether any local client cares about that room before forwarding over WebSocket. This avoids per-user pattern churn for ephemeral events.
Scaling notes
- Each node holds one long-lived subscription stream. Patterns on that stream are modified dynamically as users connect and disconnect — no reconnect needed.
- Pattern additions and removals are acknowledged by the server with a
patterns_updatedframe so you know when routing has taken effect. - For extremely high client counts, consider batching pattern changes rather than adding/removing one pattern per client connection.