Distributed Presence
vix::realtime::DistributedPresence defines the contract for sharing presence information across multiple Realtime runtime nodes.
It extends the normal PresenceStore interface with node heartbeats and backend health information.
Node A ──┐
|
Node B ──┼── shared presence backend
|
Node C ──┘Presence remains non-authoritative application information. Authoritative room state continues to belong to persisted events and RoomState.
Current implementation status
Realtime currently provides the DistributedPresence interface, but does not include a built-in Redis, PostgreSQL, or other concrete distributed presence backend.
The default runtime uses:
vix::realtime::LocalPresenceStorewhich is process-local.
DistributedPresence is the public contract for applications that need to provide a shared presence backend.
PresenceStore compatibility
DistributedPresence inherits from:
vix::realtime::PresenceStoreA distributed implementation must therefore support the normal presence operations:
upsert
find
touch
mark present
mark detached
mark left
list room
list session
erase
prune stale
clear room
clear sessionIt additionally manages runtime-node presence.
Local node
Every distributed backend identifies its local runtime node:
const auto &nodeId =
presence->local_node_id();The node identifier distinguishes one Realtime runtime from another.
node-1
node-2
node-3Node heartbeat
A distributed backend publishes the local node heartbeat through:
presence->heartbeat();The heartbeat indicates that the runtime node is still active.
Conceptually:
node-1
|
heartbeat
|
v
shared presence backendA heartbeat can also include non-authoritative node metadata:
vix::realtime::JsonObject metadata;
metadata.set_string("region", "east");
presence->heartbeat(
vix::realtime::SystemClock::now(),
std::move(metadata));The backend implementation decides how that heartbeat is persisted and shared.
Find a node
Find one known runtime node with:
auto node =
presence->find_node(
vix::realtime::NodeId{"node-1"});If the node is unknown:
node.has_value(); // falseA known node contains:
NodeId
last heartbeat time
local flag
metadataList nodes
List all known nodes with:
auto nodes =
presence->nodes();Implementations should return them in deterministic node identifier order.
Active nodes
Find nodes whose heartbeat is still recent:
auto nodes =
presence->active_nodes(
vix::realtime::SystemClock::now(),
std::chrono::seconds{30});A node is active when its last heartbeat is newer than the specified timeout.
For example:
node-1 last seen 5s ago
node-2 last seen 12s ago
node-3 last seen 40s ago
timeout = 30s
active:
node-1
node-2Check one node
Check whether one node is active with:
bool active =
presence->node_active(
nodeId,
vix::realtime::SystemClock::now(),
std::chrono::seconds{30});The node must exist and its heartbeat must still be recent.
Stale nodes
DistributedPresenceNode can check whether its heartbeat is stale:
bool stale =
node.stale(
vix::realtime::SystemClock::now(),
std::chrono::seconds{30});A timeout less than or equal to zero treats the node as stale.
Prune stale nodes
A distributed implementation can remove expired node records:
auto removed =
presence->prune_stale_nodes(
vix::realtime::SystemClock::now(),
std::chrono::seconds{30});The return value is the number of removed node records.
The backend may also remove presence records belonging to those nodes according to its own policy.
Clear one node
Remove all presence owned by one node with:
auto removed =
presence->clear_node(nodeId);This operation is useful when a runtime node is intentionally removed from the shared presence system.
It returns the number of removed presence records.
Backend status
A distributed presence backend reports one of three states:
Healthy
Degraded
UnavailableRead it with:
auto status =
presence->distributed_status();Healthy
healthymeans the shared backend is reachable and operating normally.
Degraded
degradedmeans the backend remains usable but is experiencing partial failures.
Unavailable
unavailablemeans the shared backend cannot currently provide its normal service.
Ping the backend
Check whether the shared backend responds with:
bool available =
presence->ping();ping() is intended as a lightweight backend reachability check.
It does not determine whether a particular session or node is present.
Distributed presence and room presence
A distributed backend still stores normal logical presence records.
For example:
room-1
|
+---- session-1 on node-1
+---- session-2 on node-2Because DistributedPresence implements PresenceStore, normal Realtime operations can continue using presence concepts such as:
Present
Detached
LeftThe difference is where those records are coordinated.
LocalPresenceStore
one process onlycompared with:
DistributedPresence
shared coordination backend
multiple runtime nodesDistributed presence is not room ownership
Distributed presence and room ownership solve different problems.
DistributedPresence
where sessions and runtime nodes are present
RoomDirectory
which node owns a roomKnowing that node-2 is active does not by itself mean that node-2 owns a particular room.
See Room Ownership for room ownership semantics.
Distributed presence is not authoritative state
Presence should not contain application facts that must survive replay.
For example:
player score
document contents
match resultbelong in authoritative room events and RoomState.
Distributed presence is intended for information such as:
session participation
connection state
runtime node
last activity
node heartbeatThe separation remains:
RoomState
authoritative application state
DistributedPresence
shared runtime participationImplementing a backend
A custom backend derives from:
class MyPresence
: public vix::realtime::DistributedPresence
{
// Implement PresenceStore
// and DistributedPresence operations.
};The implementation must provide both:
normal presence storage
+
node coordinationA backend could use a shared system such as PostgreSQL, Redis, or another coordination service, but Realtime does not currently provide those concrete distributed implementations.
Main model
The distributed presence contract is:
Realtime Node
|
+---- heartbeat
|
+---- session presence
|
v
DistributedPresence
|
v
shared backendThe interface defines how multiple runtime nodes can share presence and node-health information while keeping presence separate from authoritative room state.
Continue with Metrics for runtime counters and duration measurements.