-
Notifications
You must be signed in to change notification settings - Fork 47
Presence
Presence is knowledge of who is currently connected to a room and what they're doing. It gets more complex as connections to a room get more widely distributed. This wiki page tries to set out a basic definition of concepts related to presence, and outlines implementations for varying degrees of distributedness.
A server is a node in the network that connects users to rooms. It is responsible for maintaining each connected user's view of the presence state in a room. Each server has a unique server ID within its lifetime.
A cluster is a collection of servers coordinating to maintain "local" knowledge about a room. Essentially, all servers in a cluster are one hop away from any coordinating nodes. In practice, this is a single EC2 region in AWS, centered around a postgresql instance for broadcasting events and an etcd instance for server coordination.
A federation is a collection of clusters cooperating to provide a global network. At this time federation is beyond the scope of this project, but we'd like to keep it open as a possibility.
An event is a timestamped occurrence that establishes a new presence fact. Events cover connection-level actions like joining a room or getting disconnected, as well as client-side activity such as moving the input cursor or engaging with the keyboard. Events generally originate from a client socket, either from the client itself, or from the server observing the client.
Identity refers to how a user expresses their presence on the site. An identity may be reused across rooms and across connections over time. It consists of a user ID, which is globally unique (and may be a throwaway value for strongly anonymous users).
A session is the combination of a connection between a client and a room, with some details about who the client is. A session has a globally unique session ID. It is also paired with an identity.
Presence state is a collection of attributes or facts about a session's presence. For example, a a presence may or may not be connected. A user might be afk, or typing. This state could incorporate anything that the client wishes to share. An event is broadcast whenever there is a change to this state.
A snapshot of presence for a room might look like this:
[ { "session": {
"id": "100-001",
"identity": {
"id": "001",
"name": "intortus",
"state": {"typing": true, "message_id": "0001xf4a"}
},
"server_id": "100"
},
{ "session": {
"id": "101-002",
"identity: {
"id": "002",
"name": "chromakode",
"state": {"message_id": "0001xf13"}
}
"server_id": "102"
}
]
If there were only one server per room, presence would be easy. The server could just maintain global state in its own memory and manage its own broadcasting of events. This is trivial, but also a good starting point for laying out more complex notions later.
For our purposes, a cluster is a collection of closely coordinated servers. By closely coordinated, we mean sharing a common database and authority for distributing rooms. In practice, this corresponds to a single region in AWS.
Because each server is one hop away from the postgresql master, we can assume the feed of presence events from each one is mostly reliable. That is, as long as all servers are up and running, broadcasting presence events for their own sessions and keeping up with the stream of events broadcast through postgresql, we can expect close to perfect knowledge across the cluster. This is the steady state.
Unfortunately there are exceptions to the steady state. We have to reach it in the first place, as servers connect to the cluster. We also need to account for when servers become unreliable.
Each server in a cluster must broadcast a periodic heartbeat. This lets the network know that presence state associated with the server's ID is still valid.