Redis backend: lets several socketelx nodes behave as one.
What lives in Redis
| Concern | How |
|---|---|
| Broadcasts | One pub/sub channel per app (<prefix>:events). A node delivers to its own sockets first, then PUBLISHes; every other node's subscriber re-delivers locally. Each message carries the sender's node_id so a node ignores its own. |
| Presence | Hash per channel (<prefix>:presence:<channel>, socket_id -> {user, info, node}). A Lua script decides atomically whether a join is the user's first connection (or a leave their last) across all nodes, so member_added / member_removed fire exactly once cluster-wide. |
| Occupancy | Hash per channel (<prefix>:subs:<channel>, node_id -> local subscriber count) so channel_occupied / channel_vacated fire once cluster-wide and subscription counts are cluster-wide. |
| Liveness | Each node refreshes a TTL key (<prefix>:node:<node_id>). A janitor (see Socketelx.Backend.Redis.Janitor) removes presence/occupancy left behind by nodes whose key expired. |
Failure behaviour
A Redis error never crashes a websocket connection. Operations log and fall back to node-local behaviour, so during a Redis outage each node keeps serving its own clients (cross-node delivery pauses). Pub/sub is at-most-once, like Pusher itself: messages published while a node is disconnected from Redis are not replayed.
Redis Cluster
Set redis_cluster: true (SOCKETELX_REDIS_CLUSTER=true) and point the Redis URL at
any node of the cluster. Every key of an app then carries the same hash tag, so they
live in one slot, on one node: the Lua scripts keep working, and the app follows
that slot through failovers and resharding (see Socketelx.Backend.Redis.Topology).
Different apps get different tags and may land on different nodes. Broadcasts use
ordinary pub/sub, which Redis Cluster propagates to every node.
Without redis_cluster, use a single Redis endpoint: standalone, Sentinel, or a
managed primary/replica service all work.
Summary
Functions
Re-publishes this node's live state into Redis after Redis lost it (a restart, a flush, a failover to an empty replica) or after this node was cut off from Redis for a while. Called by the janitor.
Functions
Re-publishes this node's live state into Redis after Redis lost it (a restart, a flush, a failover to an empty replica) or after this node was cut off from Redis for a while. Called by the janitor.
Channel occupancy is rebuilt here in one pipeline, by setting this
node's subscriber count per channel to what the local Registry holds —
an overwrite, not an increment, so calling it again is harmless. Presence
entries need per-socket user info that only the sockets have, so each
socket is asked to restore its own (spread over a couple of seconds so
thousands of sockets don't hit a freshly restarted Redis at once).
Nothing is announced: clients were already told about these members, and
member_added for them again would be wrong.