Client Presence
ConvergeDB automatically tracks connected clients via a built-in system kind called convergedb_connections. Each connected source gets an entity in this kind, asserted on connect and retracted when the client disconnects (after its liveness deadline expires). You can subscribe to this kind like any other to observe who is online.
How it works
Section titled “How it works”When a client connects, the server automatically:
- Asserts an entity in
convergedb_connectionsusing the client’s own source ID. The entity contains the client’sName(fromConvergenceOptions) and aLastSeenAttimestamp. - Updates the
LastSeenAttimestamp on every heartbeat (default: every 15 seconds). - Retracts the entity via the standard liveness mechanism when the client disconnects and its liveness deadline expires.
Because this uses the same convergence model as user-defined kinds, brief disconnects within the liveness deadline window do not cause the entity to disappear. The client will reconnect and re-assert before the deadline fires.
Providing a client name
Section titled “Providing a client name”Set the Name property on ConvergenceOptions to give your client a human-readable identity:
var client = await ConvergenceClient.ConnectAsync(new ConvergenceOptions{ Host = "127.0.0.1", Port = 3727, SourceId = 1, Name = "player-service",});If Name is null or omitted, the entity is still created but the Name field will be empty.
Subscribing to connections
Section titled “Subscribing to connections”The Connections property on ConvergenceClient is a pre-resolved KindHandle<ConvergeDbConnection> that is ready to use immediately after connecting. No registration or resolution step is needed.
await foreach (var change in client.Connections.SubscribeAsync(bootstrap: true)){ switch (change.Type) { case NotificationType.Bootstrap: case NotificationType.Created: Console.WriteLine($"Online: {change.Entity?.Name} (last seen {change.Entity?.LastSeenAt})"); break; case NotificationType.Deleted: Console.WriteLine($"Offline: source disconnected"); break; case NotificationType.Updated: // LastSeenAt was refreshed by a heartbeat break; }}With bootstrap: true, the subscription first delivers a snapshot of all currently connected clients, then transitions to live notifications. This gives you a complete view of who is online from the start.
Querying a specific connection
Section titled “Querying a specific connection”ConvergeDbConnection? conn = await client.Connections.QueryAsync(entityId);The entity ID for a given source is deterministic: byte 0 is the source ID, bytes 1-31 are zero. You can construct it directly if you know the source ID:
byte[] id = new byte[32];id[0] = sourceId;var entityId = new ReadOnlyMemory<byte>(id);Snapshot
Section titled “Snapshot”To get a one-shot list of all connected clients without maintaining a subscription:
IReadOnlyList<ConvergeDbConnection> online = await client.Connections.BootstrapSnapshotAsync();The ConvergeDbConnection type
Section titled “The ConvergeDbConnection type”ConvergeDbConnection is a built-in entity type included in the SDK. It implements IConvergenceEntity<ConvergeDbConnection> and does not require a source generator.
| Property | Type | Description |
|---|---|---|
EntityId | ReadOnlyMemory<byte> | 32-byte entity ID (byte 0 = source ID). |
Name | string | Human-readable name from ConvergenceOptions.Name. |
LastSeenAt | DateTimeOffset | UTC timestamp of the most recent heartbeat or connect. |
System kinds
Section titled “System kinds”convergedb_connections is the first system kind in ConvergeDB. System kinds are entity kinds managed by the server itself, not by user code. They share the same convergence semantics, subscription model, and wire protocol as user-defined kinds.
System kinds use the reserved convergedb_ name prefix. Attempting to create a user-defined kind with this prefix will fail with an error.
Interaction with source epochs
Section titled “Interaction with source epochs”System kind entities are excluded from source epoch reconciliation. When you call EpochAsync, the server will not retract your connection presence entity, even if you do not re-assert it during the epoch. This is handled automatically.