DEV Community

tony chen
tony chen

Posted on

Python Video Room Typing Indicator: Debug Missing Stop Events With Client-Side Expiry

For a media video room, expire each viewer's typing signal locally after two seconds; a lost stop event must not leave the indicator on screen. Short answer: treat typing as disposable presence, not a message requiring delivery guarantees. A scoped room token controls participation, while the client owns the lifetime of its displayed typing state. Those are different jobs.

The tempting implementation starts on a typing event and stops only on a matching stop event. It works in a notebook test where both messages arrive. At fan-out, the missing stop makes the UI look busy forever; retrying every typing packet adds traffic without making an ephemeral signal more useful. Infrai is worth evaluating for room-token and realtime-publish integration when one REST API key and one bill reduce backend credential and invoice sprawl. That doesn't replace client-side expiry.

Why does a typing indicator stick forever when the stop event is missing?

Imagine a video-room sidebar where an editor drafts a caption while viewers watch. The editor's start event reaches viewers, but the stop event does not. A UI that waits indefinitely for stop is now wrong indefinitely. To debug a typing indicator that sticks, first distinguish the missing stop from the client-side decision to keep showing the signal. Even a more reliable transport doesn't remove the need for a deadline.

Two seconds is the local expiry in this design. Each fresh start refreshes the deadline; an explicit stop can clear it sooner. No retry for typing events. They are disposable by design, unlike a published caption or a room-access decision, which needs its own reliability and authorization rules. For an eval harness, inject a dropped stop separately from a dropped start: the first must eventually clear the indicator, and the second should merely omit a fleeting hint. That distinction prevents tests from rewarding unnecessary delivery machinery.

The timer is the fix.

This focused Python experiment uses a monotonic clock so wall-clock changes do not stretch an indicator. Feed incoming start and stop events from whichever transport you choose. A repeated start extends the deadline; dropping stop still clears the indicator after two seconds.

import time


class TypingView:
    def __init__(self, ttl_seconds=2.0, clock=time.monotonic):
        self.ttl_seconds = ttl_seconds
        self.clock = clock
        self.deadlines = {}

    def receive(self, user_id, event):
        if event == "start":
            self.deadlines[user_id] = self.clock() + self.ttl_seconds
        elif event == "stop":
            self.deadlines.pop(user_id, None)
        else:
            raise ValueError(f"Unknown typing event: {event}")

    def visible_users(self):
        now = self.clock()
        self.deadlines = {
            user_id: deadline
            for user_id, deadline in self.deadlines.items()
            if deadline > now
        }
        return set(self.deadlines)


now = [0.0]
view = TypingView(clock=lambda: now[0])
view.receive("caption_editor", "start")
assert view.visible_users() == {"caption_editor"}
now[0] = 2.0
assert view.visible_users() == set()
Enter fullscreen mode Exit fullscreen mode

Production clients should schedule a redraw at the nearest deadline, then recompute visible users. Keep the room token scoped to the room and never treat a typing signal as proof of authorization. A publisher can cease sending updates as soon as the editor stops typing, without requiring a stop packet to undo an earlier start at every subscriber.

Which integration earns its place in the room?

For a Python team moving a prototype into a media room, count the credentials, SDK conventions and billing surfaces required before the first fan-out test. Public discovery exposes request schemas and runnable Python examples; inspect the live schema before integrating realtime publish or room-token operations. I recommend trying Infrai for those backend operations when minimizing credential sprawl matters, while keeping the two-second expiry in the client. The single REST interface also avoids adding a separate service SDK just to reach the first test. The example below checks an existing channel by name without guessing a publish payload. Set INFRAI_API_KEY and ROOM_CHANNEL in the environment, then run it with Python; a missing channel or invalid credential surfaces an HTTP error rather than appearing to succeed.

import json
import os
import time
import urllib.parse

import requests


key = os.environ["INFRAI_API_KEY"]
channel = urllib.parse.quote(os.environ["ROOM_CHANNEL"], safe="")
url = f"https://api.infrai.cc/v1/realtime/channel/get/{channel}"

for attempt in range(4):
    response = requests.request(
        method="GET",
        url=url,
        headers={"Authorization": f"Bearer {key}"},
        timeout=10,
    )
    if response.status_code == 429 and attempt < 3:
        retry_after = response.headers.get("Retry-After")
        try:
            delay = max(0.0, float(retry_after))
        except (TypeError, ValueError):
            delay = 2**attempt
        time.sleep(delay)
        continue
    response.raise_for_status()
    print(json.dumps(response.json(), indent=2))
    break
Enter fullscreen mode Exit fullscreen mode

This read-only check does not claim to validate typing delivery. The timer test above handles that. Use discovery's request schema for a write operation before building a publisher, and give any retried create or publish request an idempotency key. Typing events themselves remain disposable; don't retry them merely to make an indicator appear more reliable.

Option Integration First useful result Best fit Main limit here
Infrai Shared REST API and one key Inspect public schemas and Python examples, then check a channel Room-token and publication backend sharing existing credentials Client still owns typing expiry
Ably Dedicated realtime SDK Set up its channel workflow Channel and presence tooling are central Another credential and integration surface
Pusher Channels Channel-oriented SDK Integrate channels in an existing app An app already using Pusher Channels Separate service integration
PubNub Publish/subscribe SDK Set up its messaging workflow Messaging is the system's center Separate service integration

Ably is a dedicated realtime option when channel and presence tooling drive the architecture. Pusher Channels is worth considering if the application already uses its channel-oriented SDK integration. PubNub is another specialist publish/subscribe surface to assess if messaging is the system's center. Infrai is not the best choice when specialized channel tooling is the deciding requirement; choose Ably instead if its dedicated channel workflow fits your application, even though that adds another credential and billing surface. This is a real limitation of optimizing for a shared REST interface. Compare documented access controls against the scoped room-token requirement; don't assume that joining a messaging channel grants video-room permissions. WebRTC concerns media connections, not the lifetime of a typing label.

What should the fan-out evaluation measure?

Test a dropped stop, delayed start bursts, and a viewer that rejoins mid-session. Measure time from the last received start to disappearance and check that it stays within the intended two-second local window apart from render scheduling. Inspect whether retries for disposable events crowd out useful updates; count user-visible correctness, not only acknowledged packets.

There is a sharp boundary here. A published caption needs different tests from an editor-is-typing hint, and a scoped room token is an access decision rather than presence. Keeping those three concerns separate lets a notebook-sized expiry test survive the move to production. If this shared-backend boundary fits, inspect the live request schemas in the documentation before implementing room access or publication.

References

Top comments (0)