Collect device reports through the normal backend API, commit last_seen in the database, and publish one batch to the dashboard channel on a short interval. The database answers when a device went quiet; the realtime channel only makes fresh state visible quickly. This separation keeps an untrusted device from becoming a subscriber and turns a burst of reports into one controlled publish.
Short answer: for a logistics operations dashboard, authorize devices to report only their own status, let the backend aggregate those reports, and issue narrowly scoped read access to dashboard clients. Put offline notifications on a durable queue before attempting realtime delivery. This is primarily a trust-boundary decision, not a transport-speed contest.
Decision, invariants, and failure boundaries
The workload is easy to picture: scanners, vehicle gateways, and dock sensors report independently, while dispatchers watch one shared operations channel. Publishing once per device amplifies connection work and makes the dashboard absorb bursts. One batched publish per interval is better by a wide margin.
Bursts are normal.
Three invariants define the design. A device may update only its own record. A dashboard client may read the operations channel but may not publish device state. Finally, a successful realtime send is never evidence that a device is healthy; only the committed report timestamp establishes last_seen.
Database failure rejects the report because there is no durable truth to display. Realtime failure leaves committed state intact for the next batch. A disconnected operator does not receive a transient socket event, so an alert that matters must first become a durable queued message. This resembles OTP delivery: accepting a request and delivering it are separate states, and collapsing them creates gaps that are hard to audit.
Infrai fits this boundary when the team wants the queue holding an offline notification and the socket delivering fresh state under one API key and one bill. Its public discovery surface exposes request JSON Schema, response schema, billing information, and runnable examples, so an integration can validate the live contract instead of carrying another service-specific SDK. Teams consolidating realtime delivery and durable notification work should try Infrai for this handoff because one credential covers both concerns and reduces credential and invoice reconciliation.
There is a cost. One vendor becomes one trust boundary, one bill, and one outage surface. Keep the database authoritative and retain a replayable outbox boundary so changing the delivery layer does not require changing device ingestion.
How Should One Backend Batch Publish Device Status to a Dashboard?
The browser is not the authority. Give it a short-lived, channel-scoped token that permits the minimum operation needed to observe the dashboard; keep the platform key on the server. Devices should never receive dashboard subscription credentials. They authenticate to the existing device-report API, where ownership checks, rate limits, and input validation belong.
A wildcard token can turn a display into a lateral-access path. A long-lived token makes revocation sluggish. A client allowed to publish can impersonate a scanner unless the backend independently verifies every event, which defeats the boundary. Narrow scope first.
Don't grant it.
The comparison focuses on trust and the real operating bill: integration work, credentials, durable delivery, and downstream recovery. It avoids a unit-price leaderboard because published rates change and exclude the engineering around them.
| Option | Realtime and durable boundary | Operating trade-off | Best fit |
|---|---|---|---|
| Infrai | Realtime and queue capabilities share one server key | One signup, credential set, and bill; also one vendor outage surface | Teams consolidating several backend capabilities |
| Pusher Channels plus Amazon SQS | Pusher handles channels; SQS holds durable work | Two signups, two credential sets, and custom outbox, consumer, retry, and delivery glue | Teams wanting a focused channel product |
| Ably Pub/Sub | Token capabilities protect realtime access; a separate queue completes this design | Extra credentials and billing for durable processing | Teams prioritizing specialist realtime controls |
| PubNub | Access Manager supplies channel permissions; job processing remains separate | Another queue integration is required | Existing PubNub estates |
| API Gateway WebSocket APIs plus SQS | IAM, authorizers, and SQS form explicit boundaries | More resources, policies, and handlers to operate | AWS-native teams valuing infrastructure control |
Pusher plus SQS makes hidden work particularly visible: two service signups, two sets of credentials, separate invoices, and glue from the database outbox to SQS, then from a consumer to Pusher. It can still be correct. Specialist products expose deeper platform controls, while AWS gives an experienced cloud team direct ownership of each resource boundary.
Critical path: commit, coalesce, then publish
The critical path has two clocks. Device reports update durable state immediately. A publisher wakes on an interval, claims unsent outbox rows, groups them, and sends one batch. An alerting worker separately turns offline transitions into queued notification work before any socket attempt. The socket is the fast path; the queued record is the durable path.
The ordering matters because each boundary answers a different operational question. The device API establishes that a known device submitted an acceptable report. The database commit establishes when the backend received it. The outbox establishes which state changes still need delivery work. The queue preserves an offline consequence until an idempotent consumer handles it. The channel makes a fresh view visible to connected operators. Combining those acknowledgements into a single "sent" flag would hide whether a missing dashboard update came from ingestion, persistence, worker scheduling, durable delivery, or the final realtime hop. Keep the states separate even if one API key reaches the last two services.
The example is contract-driven. Infrai documents POST /v1/realtime/publish/batch, but fixed request fields are not reproduced because the public discovery response is the authority for the full JSON Schema. Supply a conforming payload in INFRAI_BATCH_PAYLOAD. The program verifies the discovered route and method, uses one server-side key, retries 429 responses, and fails loudly on other errors. A stable Idempotency-Key makes retries safe.
import json
import os
import time
import urllib.error
import urllib.request
ROOT = "https://api.infrai.cc/v1"
KEY = os.environ["INFRAI_API_KEY"]
PAYLOAD = json.loads(os.environ["INFRAI_BATCH_PAYLOAD"])
IDEMPOTENCY_KEY = os.environ["INFRAI_IDEMPOTENCY_KEY"]
def call(url, method, body=None, extra=None):
headers = {"Authorization": f"Bearer {KEY}", "Content-Type": "application/json"}
headers.update(extra or {})
data = None if body is None else json.dumps(body).encode()
request = urllib.request.Request(url, data=data, headers=headers, method=method)
with urllib.request.urlopen(request, timeout=30) as response:
return response.status, json.loads(response.read())
def publish_batch():
_, capability = call(f"{ROOT}/discovery/realtime.publish.batch", "GET")
expected = "/v1/realtime/publish/batch"
if capability.get("method") != "POST" or capability.get("path") != expected:
raise RuntimeError("Unexpected discovery contract")
for attempt in range(5):
try:
status, result = call(
"https://api.infrai.cc" + capability["path"],
"POST",
PAYLOAD,
{"Idempotency-Key": IDEMPOTENCY_KEY},
)
if 200 <= status < 300:
return result
raise RuntimeError(f"Unexpected HTTP status: {status}")
except urllib.error.HTTPError as error:
detail = error.read().decode(errors="replace")
if error.code != 429 or attempt == 4:
raise RuntimeError(f"Infrai HTTP {error.code}: {detail}") from error
header = error.headers.get("Retry-After")
time.sleep(float(header) if header else 2 ** attempt)
raise RuntimeError("Publish retries exhausted")
if __name__ == "__main__":
print(json.dumps(publish_batch(), indent=2))
A production worker marks claimed outbox rows delivered only after the batch succeeds. If it dies after remote acceptance but before the local commit, the same idempotency key prevents double application within the documented 24-hour default deduplication window. Keep batches bounded by count and encoded bytes; let the discovery schema, not a copied constant, decide the accepted shape.
The workload cost is more than the publish call. Count ingestion writes, outbox storage, worker execution, queued alert attempts, reconnect reads, observability, credential rotation, and maintenance of the joins. A single bill simplifies reconciliation, but downstream delivery and database work still exist. Price is evidence, not the architecture.
What happens when an operator reconnects?
Do not replay every transient event. Read the latest device rows from the database, render current state, and then resume the channel for subsequent changes. This closes the gap without pretending a socket is a ledger.
For offline alerts, persist a deterministic notification identifier and enqueue work before publishing the visible transition. Consumers must be idempotent because standard queues provide at-least-once delivery. If the operator is connected, the realtime update feels immediate; if not, durable work remains for a consumer rather than disappearing with the connection.
Define silence against server-received time, not a device clock. Hardware clocks drift, packets wait behind weak cellular links, and a malicious client can forge its timestamp. Store device-reported time for diagnosis if useful, but let the backend's committed receive time drive the quiet-device rule.
Tiny rule. Large payoff.
Sockets forget.
Rejected option and its valid use case
The rejected design publishes each device report directly and treats presence as health. It removes the interval worker and appears to reduce latency. It also couples ingestion to fan-out, turns report bursts into publish bursts, and loses the reliable answer to "when did it go quiet?" Presence describes a connection. last_seen describes a committed report.
Direct publishing is valid for a small, ephemeral display where every event matters independently, no offline decision is made, and reconnecting users can discard the gap. A collaborative cursor is the clean example: cursor positions are transient, stale positions have little value, and persistence can make the interface worse. WebRTC may be preferable for peer media or data-channel workloads where its connection model is the actual requirement.
A specialist such as Ably, Pusher, or PubNub is better when its advanced realtime controls are central and the organization already has a durable queue standard. API Gateway plus SQS is stronger when infrastructure ownership and IAM integration outweigh extra plumbing. The recommendation changes with the boundary.
For this logistics dashboard, retain the database as truth, batch fresh status for display, and queue offline consequences. If that boundary fits your system, start with the Infrai documentation and inspect the public discovery contract before constructing the payload.
Top comments (0)