v3: Host Failover¶
This scenario continues from the host topology session: a running host + webrtc star loses
its host. The server signals the departure with PlayerLeft, re-elects a host over the remaining
members, and sends every survivor a fresh SessionPlan with the new host and fresh per-recipient ICE.
Starting state — a finalized host + webrtc session:
- Alice, id
00000000-0000-0000-0000-00000000000a— the current (elected) host. - Carol, id
00000000-0000-0000-0000-00000000000c— a client. - Dave, id
00000000-0000-0000-0000-00000000000d— a client. - Room
11111111-1111-1111-1111-111111111111, codeABC123,supports_authority: true.
All three negotiated v3 plus the host topology and webrtc transport, so all three are electable.
1. The host departs¶
Intent: the host disconnects (an explicit LeaveRoom, or a dropped socket). Either way, the server removes Alice
from the room and notifies the remaining members.
If Alice left cleanly she sent:
The server signals the departure to v3 survivors with PlayerLeft plus Alice's
terminal relay watermark:
{
"type": "PlayerLeft",
"data": {
"player_id": "00000000-0000-0000-0000-00000000000a",
"epoch": 1,
"final_seq": 0
}
}
Here Alice sent no relayed game data in this incarnation, so final_seq: 0
lets each client retire her accounting cursor immediately. V2 recipients see
the frozen player_id-only projection.
Both Carol and Dave receive this PlayerLeft.
Next: the departed Alice was the session host, so the server detects that the stored host is now invalid and re-elects.
2. The server re-elects a host¶
Intent: the session's topology and transport are sticky for its lifetime, so the server does not re-run the
selection ladder. It only re-elects a host over the members that can still run the session — those that negotiated
v3 plus the session's host topology and webrtc transport. Among them the rule is authority preferred, else
earliest joiner, with a smaller-UUID tie-break.
With Alice gone, the remaining electable members are Carol (...000c) and Dave (...000d). Neither is the room
authority now, so the tie-break falls to earliest joiner; assume Carol joined first, so Carol is re-elected
host.
There is no distinct "host changed" message — the re-election is communicated entirely through a fresh
SessionPlan to each survivor.
Next: the server mints fresh per-recipient ICE and sends each remaining v3 member a new plan.
3. Survivors receive a fresh SessionPlan¶
Intent: each remaining member receives a re-issued SessionPlan — same topology and transport, new host, fresh
ICE. The plan supersedes the previous one: clients apply the latest plan and reconnect per peers[].initiate.
The new host, Carol, receives a plan listing the remaining client(s) — here just Dave — with initiate: false
(the host answers each client):
{
"type": "SessionPlan",
"data": {
"generation": "00000000-0000-0000-0000-00000000000e",
"topology": "host",
"transport": "webrtc",
"host": "00000000-0000-0000-0000-00000000000c",
"peers": [
{
"player_id": "00000000-0000-0000-0000-00000000000d",
"player_name": "Dave",
"is_authority": false,
"initiate": false
}
],
"ice_servers": [
{ "urls": ["stun:stun.l.google.com:19302"] },
{
"urls": ["turn:turn.example.com:3478"],
"username": "1700009900:00000000-0000-0000-0000-00000000000c",
"credential": "Cf9aZ8b7Yc6Xd5We4Vf3Ug2Th1Si0Rj="
}
],
"fallback": "relay"
}
}
The remaining client, Dave, receives a plan whose single peer is the new host Carol, initiate: true,
is_authority: true:
{
"type": "SessionPlan",
"data": {
"generation": "00000000-0000-0000-0000-00000000000e",
"topology": "host",
"transport": "webrtc",
"host": "00000000-0000-0000-0000-00000000000c",
"peers": [
{
"player_id": "00000000-0000-0000-0000-00000000000c",
"player_name": "Carol",
"is_authority": true,
"initiate": true
}
],
"ice_servers": [
{ "urls": ["stun:stun.l.google.com:19302"] },
{
"urls": ["turn:turn.example.com:3478"],
"username": "1700009900:00000000-0000-0000-0000-00000000000d",
"credential": "Dg0bA9c8Zd7Ye6Xf5Wg4Vh3Ui2Tj1Sk="
}
],
"fallback": "relay"
}
}
Next: Dave tears down its dead connection to the old host and offers to the new
host Carol (Signal{to: Carol, generation: G, Offer}); Carol answers using the
same new generation. The exchange is identical in shape to the
host topology step 2, just with Carol as the host. ICE
trickle and TransportStatus reporting proceed as before.
Notes¶
- The relay floor never closed. While the new WebRTC edges are being re-established, Dave and Carol can keep
exchanging
GameDataover the relay (the universalfallback). Failover never interrupts the session's data path. - If no member qualifies, the server sends every remaining v3 member an explicit Relay/Relay reset with a
fresh generation and no host, endpoint, peers, or ICE servers. The session ends and the room stays on relay. For
example, if the only other member were a relay-only member (possible only through a reconnect with downgraded
capabilities — new seat-fills into a running session are rejected with
ROOM_SESSION_INCOMPATIBLE), the server would not name it host of a session it cannot run. - An ex-host that reconnects is paired as a client of the re-elected host, because the stored host is now the
new one. The reconnecting member learns this from the fresh
SessionPlanit receives on entry (see the reconnection scenario).