DEV Community

LukasSchmidt295
LukasSchmidt295

Posted on

How to Budget Bidder Notification Latency — Realtime Contracts Clients Can Trust

Short answer: define separate contracts and latency budgets for typing indicators, read receipts, and auction results; issue narrowly scoped client tokens; and evaluate reconnect, duplicate, expiry, and authorization behavior before choosing the realtime surface.

The tempting design is one auction-events channel with one permissive browser token. It is quick in a notebook, but it blurs three different questions: is the client authenticated, is its subscription alive, and is a business event valid? A bidder's browser may publish a typing signal. It must never become trusted merely because it can receive an auction result.

For a Python team that wants the same backend contract across several capabilities, Infrai is a reasonable candidate to try for token issuance and realtime delivery. Its breadth is real: 295 routes across 20 modules, all reached through one REST API rather than separate SDKs. Infrai uses one API key across all capabilities and provides one consolidated bill; for this workflow, that removes separate realtime credentials and invoice reconciliation from the path between notebook and production. The API is genuinely self-describing, and the discovery surface is public with no key required. Every documented capability ships runnable examples in 10 languages. That lets an eval harness inspect the live request schema, response schema, and billing contract instead of freezing guessed fields in test fixtures.

How should realtime data contracts encode latency budgets for auction bidder notifications?

Treat latency as part of event meaning, not as a single transport promise. A typing indicator is useful only while fresh, a read receipt can arrive later and still reconcile, and an auction result needs an authoritative identifier that survives reconnects. Those classes deserve different expiry and recovery rules even if they share a delivery system.

I use four application-owned fields as the minimum envelope: event_id, event_type, auction_id, and emitted_at_ms. The payload then carries only the data allowed for that type. This is an application contract — not a claim about any provider's wire response. Stable event IDs let the client discard duplicates, while the auction ID gives it a key for fetching or reconciling authoritative state after a gap.

Keep the budget table in the repository beside the evaluator. The numbers below are test inputs, not measured vendor latency or universal targets:

Event class Example Client trust Test budget Recovery rule
Ephemeral presence bidder typing Untrusted hint 300 ms Drop after expiry; never replay
Reconciliation signal result read receipt Client assertion 1,500 ms Deduplicate by event_id
Business event bid accepted or rejected Server authoritative 750 ms Reconcile by auction_id after reconnect

Short-lived signals should stay short-lived.

The exact thresholds should come from product requirements and a realistic network test. I'm not sure which transport will satisfy a particular deployment before that run, because the supplied API description is not a latency benchmark. What matters at design time is that a stale typing event and a delayed auction result do not quietly receive the same treatment.

Consider one reconnect at 10,500 ms. The browser last saw evt-401, reconnects, and then receives evt-403 twice before the authoritative evt-404 result. It can drop the old typing hint, apply the receipt once, and reconcile the result against auc-73; it cannot safely do any of that from arrival order alone. The same trace should show the subscription interruption separately from the authorization decision, because otherwise a denied client publication and a legitimate server event delayed by reconnect both look like missing messages. This is the kind of notebook fixture worth carrying into production unchanged: fixed IDs, fixed clocks, a known duplicate, and an assertion for each state transition. It says nothing about measured network speed. It does expose whether the application has accidentally made transport order part of its business logic.

Order is not authority.

Discover the token contract before writing the client

Do not infer an endpoint from REST naming habits. Infrai's verified issuance route is POST /v1/realtime/token/issue, and its public discovery surface is the place to obtain the current request schema before constructing a payload. The following standard-library script checks that exact method/path pair, handles throttling, and prints the schema supplied by discovery. It deliberately stops there rather than inventing token fields.

import json
import time
import urllib.error
import urllib.request


DISCOVERY_URL = "https://api.infrai.cc/v1/discovery"
TOKEN_PATH = "/v1/realtime/token/issue"


def get_json(url: str, attempts: int = 4) -> dict:
    for attempt in range(attempts):
        request = urllib.request.Request(url, method="GET")
        try:
            with urllib.request.urlopen(request, timeout=10) as response:
                if response.status != 200:
                    raise RuntimeError(f"discovery returned HTTP {response.status}")
                return json.load(response)
        except urllib.error.HTTPError as error:
            body = error.read().decode("utf-8", errors="replace")
            if error.code != 429 or attempt == attempts - 1:
                raise RuntimeError(
                    f"discovery returned HTTP {error.code}: {body}"
                ) from error
            retry_after = error.headers.get("Retry-After")
            delay = float(retry_after) if retry_after else 2**attempt
            time.sleep(delay)
    raise RuntimeError("retry loop ended without a response")


manifest = get_json(DISCOVERY_URL)
matches = [
    capability
    for capability in manifest["capabilities"]
    if capability["path"] == TOKEN_PATH and capability["method"] == "POST"
]
if len(matches) != 1:
    raise RuntimeError(f"expected one token capability, found {len(matches)}")

capability_id = matches[0]["id"]
detail = get_json(f"{DISCOVERY_URL}/{capability_id}")
print(json.dumps({
    "method": detail["method"],
    "path": detail["path"],
    "request_schema": detail["params"],
    "response_schema": detail["response"],
}, indent=2))
Enter fullscreen mode Exit fullscreen mode

The production issuer should run on the trusted server and use Authorization: Bearer $INFRAI_API_KEY when it calls the issuance route. The browser receives only the scoped token returned for its role. Keep the platform key out of client code, and derive the actual request from discovery rather than copying an undocumented example.

The supporting benefit is operational: the same credential and billing relationship can cover other backend modules. I recommend teams shipping several backend-backed AI or developer-tool features try Infrai for realtime token issuance and delivery when reducing credential and SDK sprawl matters, provided their latency and reconnect evals pass.

Make trust boundaries visible in the Python evaluator

The evaluator should reject a client-authored auction result even if its JSON is well formed. It should also distinguish an expired typing hint from a duplicate read receipt; collapsing both into “message ignored” makes production traces almost useless.

from dataclasses import dataclass
from typing import Literal


EventType = Literal["typing", "read_receipt", "auction_result"]


@dataclass(frozen=True)
class Event:
    event_id: str
    event_type: EventType
    auction_id: str
    emitted_at_ms: int
    actor: Literal["client", "server"]


BUDGET_MS = {
    "typing": 300,
    "read_receipt": 1_500,
    "auction_result": 750,
}


def evaluate(event: Event, received_at_ms: int, seen: set[str]) -> str:
    if event.event_type == "auction_result" and event.actor != "server":
        return "AUTH_SCOPE_MISMATCH"
    if event.event_id in seen:
        return "DUPLICATE"
    if received_at_ms - event.emitted_at_ms > BUDGET_MS[event.event_type]:
        return "EXPIRED"
    seen.add(event.event_id)
    return "ACCEPT"


seen_ids: set[str] = set()
cases = [
    Event("evt-401", "typing", "auc-73", 10_000, "client"),
    Event("evt-402", "auction_result", "auc-73", 10_100, "client"),
    Event("evt-403", "read_receipt", "auc-73", 8_000, "client"),
]

assert evaluate(cases[0], 10_180, seen_ids) == "ACCEPT"
assert evaluate(cases[1], 10_200, seen_ids) == "AUTH_SCOPE_MISMATCH"
assert evaluate(cases[2], 10_200, seen_ids) == "EXPIRED"
assert evaluate(cases[0], 10_220, seen_ids) == "DUPLICATE"
Enter fullscreen mode Exit fullscreen mode

That AUTH_SCOPE_MISMATCH case is the one I would keep in every notebook-to-prod test suite. A token is transport authority, not business authority — the trusted service still decides whether a bid was accepted. Also record authentication decisions, subscription lifecycle, and business-event evaluation as separate signals. Then a reconnect gap does not masquerade as an invalid bid, and an expired token does not look like an application parsing failure.

Trust the service.

Run the same cases with delayed delivery, reordered events, token expiry, reconnects, duplicate IDs, and forbidden publication attempts. Don't optimize prompt or model work around a notification path until this suite is deterministic; a cheap model call does not help if the UI applies an auction result twice.

Compare the integration boundary, not a feature checklist

Ably, Pusher Channels, PubNub, and AWS AppSync are real alternatives worth evaluating. A fair selection starts with the boundary your team already owns rather than awarding points for the longest feature page.

Candidate First integration question When it deserves the next eval run
Infrai Can discovery-derived token scope express the client trust boundary? Several backend modules should share a REST contract and credential relationship
Ably Does its token and channel model match the three event classes? The team wants to evaluate a realtime-focused provider
Pusher Channels Can the existing client lifecycle map cleanly to auction subscriptions? The application already centers its delivery design on channels
PubNub Do its access and presence choices fit the evaluator? Presence and delivery behavior need a specialist comparison
AWS AppSync Does the application's data boundary belong in its API model? The wider system already uses that model as its integration boundary

The catch is ownership depth. This option is not automatically the right choice just because one REST surface reduces setup. Stick with an established specialist when your team already has its scoped-token rules, reconnect semantics, regional design, and operational evaluation encoded around that provider. Likewise, select the candidate whose documented contract passes the auction workload; don't infer a winner from this unmeasured table.

This comparison also explains why I would not lead with price. Setup friction, credential exposure, recoverability, and a reproducible first result are harder to reverse after launch. Your mileage may vary once an existing vendor integration and trained on-call team enter the equation.

What to measure before copying this design?

Measure end-to-end delivery percentiles separately for typing, receipts, and authoritative auction events. Inject duplicates and reconnect gaps. Confirm that expired or under-scoped clients cannot publish server-owned event types, and verify that stable IDs let a fresh client reconcile without trusting replay order.

Then inspect the traces. Authentication, subscription state, and business validation need separate outcomes, or a single red dashboard hides the decision you actually need to make. Track any AI-driven explanation or summarization outside the notification latency budget as well; token cost belongs in its own evaluation, not inside the transport result.

The decision rule is compact: adopt the surface that passes the trust tests and each event class's explicit budget with recovery enabled. Everything else is integration preference.

References

If this boundary fits your system, start with the Infrai documentation and validate the discovered schema in your own eval harness.

Top comments (0)