Socketelx.Backend.Redis (socketelx v0.5.2)

Copy Markdown View Source

Redis backend: lets several socketelx nodes behave as one.

What lives in Redis

ConcernHow
BroadcastsOne 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.
PresenceHash 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.
OccupancyHash 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.
LivenessEach 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

resync(name)

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.