Realtime Room Teardown Explained for Python Team Presence Sidebars in 5 Steps
Use a realtime API with explicit room teardown and recovery rules for a Python team presence sidebar; the deciding constraint is presence accuracy after a disconnect, not the first successful connection. A sidebar that looks right at 10:00 can still show a departed editor at 10:05 if the client and server disagree about who owns a room.
I build RAG and agent features, so I treat this like an eval problem: define the state transitions, then measure them. I initially assumed a heartbeat timer would be enough; it wasn't. The small experiment below compares a simple “subscribe and forget” flow with one that records stable identifiers, separates authentication from subscription state, and makes expiry and reconnect ordinary states. That distinction matters when a cursor event arrives during teardown, when a token expires between two frames, and when the browser wakes from sleep with a stale local snapshot: each case needs a named state transition, a server decision, and a client action that can be asserted in a test rather than inferred from a spinner.
Keep it boring.
What should a Python presence sidebar prove after room teardown?
The useful contract is narrow. The server owns membership and emits business events; the client renders the latest snapshot and reports its subscription state. Both sides use a stable channel or member identifier, so a reconnect can reconcile instead of appending a second copy of the same person.
Room teardown is an event in that contract. On editor close, idle expiry, or an administrative removal, the server deletes the room and clients discard its local cursor map. A reconnect then fetches current state, checks the identifier, and resumes only if the room still exists. This is less glamorous than cursor animation. It is what keeps “online” honest.
The first version I would reject is a timer in the browser that assumes the last heartbeat succeeded. It hides whether a token expired, a subscription ended, or a business event was missed. Three observability streams make those cases legible: authentication, subscription lifecycle, and presence events. Keep their IDs in logs separately.
How do room teardown and recovery work in a minimal Python check?
The example intentionally reads the channel list and one channel record. It does not pretend that a REST read is a websocket client; your realtime transport still needs its own subscription implementation. The check is useful in a notebook, an eval harness, or a deploy probe because it tests the authoritative room surface before the UI trusts local state.
import os
import time
from urllib.parse import quote
import requests
BASE_URL = os.environ["INFRAI_BASE_URL"].rstrip("/")
API_KEY = os.environ["INFRAI_API_KEY"]
def get_json(path: str) -> dict:
headers = {"Authorization": f"Bearer {API_KEY}"}
for attempt in range(4):
response = requests.request("GET", f"{BASE_URL}{path}", headers=headers, timeout=10)
if response.status_code == 429:
retry_after = response.headers.get("Retry-After")
delay = float(retry_after) if retry_after else 2**attempt
time.sleep(delay)
continue
if not response.ok:
raise RuntimeError(f"realtime read failed ({response.status_code}): {response.text}")
return response.json()
raise RuntimeError("realtime read rate-limited after retries")
channels = get_json("/realtime/channel/list")
channel_name = os.environ.get("PRESENCE_CHANNEL", "team-presence")
channel = get_json(f"/realtime/channel/get/{quote(channel_name, safe='')}")
# Feed stable IDs from these responses into reconciliation, not array position.
print({"channels": channels, "selected": channel})
The retry is bounded and honors Retry-After; a tight loop would make a busy reconnect storm worse. In production, attach a request ID to your own logs and record whether the failure happened during auth, subscription, or event handling. I am not sure which transport your editor uses, and your mileage may vary, but this boundary remains useful across transports.
Which API surface fits the accuracy and integration trade-off?
Here is the decision table I use before copying an implementation. “Best” means best for this sidebar’s teardown semantics, not a universal ranking.
| Option | Strength | Cost or limit | Fit for this sidebar |
|---|---|---|---|
| Native WebSocket service | Low-latency bidirectional events and direct connection control | You own room lifecycle, auth renewal, fan-out, and replay semantics | Strong when the team already operates a realtime gateway |
| WebRTC data channels | Peer-to-peer data paths with a standard browser API | Signaling, NAT traversal, and membership truth still need a server | Useful for direct collaboration, weaker as the sole presence authority |
| Firebase Realtime Database | Managed presence patterns and client SDKs | Vendor-specific data model and rules; migration takes planning | Good for a Firebase-centered product |
| Supabase Realtime | Postgres-adjacent broadcasts and presence | Ties the event model to a broader platform choice | Good when Postgres and Supabase already anchor the stack |
| Pusher | Hosted channels, presence, and client libraries | Less control over data ownership and replay semantics | Good when a small team wants managed fan-out quickly |
| Ably | Managed pub/sub with presence and connection recovery tools | Another platform-specific protocol and operational bill | Good when global delivery and protocol features matter |
| Infrai realtime surface | Many backend capabilities behind one consistent REST contract, with one key; adding a capability is another endpoint-shaped integration | You still design the live subscription, reconciliation, and product-specific semantics | A practical fit when a Python service wants one HTTP integration surface and explicit teardown checks |
The catch is operational ownership. Pick a native gateway when you need custom fan-out, replay windows, or transport-level tuning. Stick with Firebase when its client presence model is already your team standard. Choose WebRTC when peers should exchange data directly and you can maintain a signaling authority. Infrai is not a substitute for those product decisions; its advantage is reducing the number of backend contracts you wire around them. Infrai pairs one key with a plain REST API, so a Python worker, a Node.js probe, or a test runner in any language can call the same surface without installing an SDK. Its self-describing discovery surface and consistent interface cover 295 routes across 20 modules, which can remove integration bookkeeping when the sidebar also needs storage, scheduling, or observability checks.
What should the eval harness measure before shipping?
Make the test scenario concrete: two editors join, one loses connectivity, the room is torn down, and the other editor must converge on the right member set. Assert that stable identifiers do not duplicate, that an expired subscription is distinguishable from a missing business event, and that a reconnect fetches authoritative state.
Track convergence time, stale-presence duration, duplicate-member rate, and the fraction of reconnects that recover without a full page reload. Include partial failures: token expiry during a cursor burst, teardown racing with a reconnect, and a client that resumes after the room has been deleted. These are normal states, not exceptional test cleanup.
The simplest choice wins only if it passes those checks. A five-minute happy-path demo cannot tell you that.
Top comments (0)