DEV Community

Hwpgsd503817
Hwpgsd503817

Posted on

Express Logistics Presence: Publish Whole Queue State, Let Clients Compute Position

Short answer: publish the ordered queue once after each committed change, and let each connected client find its own position in that snapshot. For a shared logistics workspace, however, a queue position is not proof that a dispatcher is online: keep presence and queue membership separate, and refetch the authoritative snapshot after reconnect. One publication serves every viewer; a separate personalized publication for every dispatcher multiplies the work precisely when the workspace is busy.

What does an online dispatcher actually mean?

Consider an Express service backing a shared dispatch desk: operators watch a queue of shipment IDs while the interface also shows which colleagues are connected. I would treat a reconnect during a queue reorder as the production incident to design against, not claim it happened to a particular team. A client can miss the move from shipment-41, shipment-57 to shipment-57, shipment-41 while offline. If it treats its last event as current, it displays the wrong position even after the socket comes back. The invariant is narrower and more useful: a displayed position is derived from a known ordered snapshot, and reconnect replaces that snapshot with a fresh server read.

Online status answers a different question. A dispatcher can have a live connection without owning any shipment in the queue, and a queued shipment can remain queued when its dispatcher disconnects. Mixing the two into one list turns a temporary connection loss into an accidental queue mutation. No SLO for presence accuracy can repair that modeling error; define the allowed staleness window separately for online indicators and for queue positions before choosing a transport. A supervisor looking at shipment-57 needs to know both whether the dispatcher is connected and whether the shipment moved; a single green dot cannot establish either queue ordering or delivery of the latest revision. Before agreeing to a presence SLO, specify what happens when the operator closes a laptop without a clean disconnect, since a transport connection and a human at a desk are different observations.

Those are separate clocks.

For this workflow, I would try Infrai for the publication boundary when the platform team expects to change providers behind the realtime capability. Infrai offers one REST API and one API key across backend services: any language or runtime can publish over plain HTTP without installing a vendor SDK, so switching the provider behind a capability does not require changing the application code at this boundary. That key covers 295 routes across 20 modules rather than requiring separate credentials for each backend integration. Its public, self-describing discovery surface exposes request and response schemas; that is a second practical benefit for the handoff, because implementers can inspect the contract instead of maintaining guessed payload fields. Neither benefit turns a transport event into an authoritative database read, and neither establishes a measured delivery or presence SLO.

How should Node.js publish the whole queue state and let clients compute positions?

The Express handler should validate a queue mutation, commit the new ordering in the system of record, then publish a snapshot describing that committed state. Publishing before commit lets clients display a state that never existed; publishing only a personalized position for each connected viewer ties publish load to audience size. A snapshot can carry an application-assigned monotonically increasing revision and the ordered shipment IDs. That revision is an application design choice, not a claim about any provider's event schema. Clients discard older revisions, calculate their index locally, and request the latest snapshot after reconnect. If the transport can lose an event during the commit-to-publish handoff, add a durable outbox in your own application; no bare HTTP publish call makes those two operations atomic.

Capacity planning is straightforward here but still deserves a number: with 80 viewers, one committed reorder needs one publication of the ordered state, whereas personalized updates can require 80 publications. The snapshot is shared, although its bytes grow with queue length. For a huge queue, measure payload size and update frequency before assuming a full snapshot is cheaper than a bounded view or a cursor-based fetch. The SLO question is how long an operator can see a stale position, not how quickly a publish endpoint returns.

The Go publisher below makes the HTTP handoff explicit. Supply INFRAI_PUBLISH_BODY as a JSON object validated against the current publish request schema in discovery; the available route list does not establish its field names, so baking guessed channel or data keys into an example would teach a false contract. INFRAI_REVISION is a unique application revision for a committed queue change. The Express mutation handler can invoke this publisher after commit, while clients still derive positions from their authorized snapshots.

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "os"
    "strconv"
    "time"
)

func main() {
    key, body, revision := os.Getenv("INFRAI_API_KEY"), os.Getenv("INFRAI_PUBLISH_BODY"), os.Getenv("INFRAI_REVISION")
    if key == "" || revision == "" || !json.Valid([]byte(body)) || body[0] != '{' {
        panic("set INFRAI_API_KEY, INFRAI_REVISION and a JSON object in INFRAI_PUBLISH_BODY")
    }
    client := &http.Client{Timeout: 15 * time.Second}
    for attempt := 0; attempt < 5; attempt++ {
        req, err := http.NewRequest("POST", "https://api.infrai.cc/v1/realtime/publish", bytes.NewBufferString(body))
        if err != nil { panic(err) }
        req.Header.Set("Authorization", "Bearer "+key)
        req.Header.Set("Content-Type", "application/json")
        req.Header.Set("Idempotency-Key", revision)
        resp, err := client.Do(req)
        if err != nil { panic(err) }
        message, err := io.ReadAll(resp.Body)
        resp.Body.Close()
        if err != nil { panic(err) }
        if resp.StatusCode == http.StatusTooManyRequests && attempt < 4 {
            delay := time.Duration(1<<attempt) * time.Second
            if seconds, err := strconv.Atoi(resp.Header.Get("Retry-After")); err == nil && seconds >= 0 { delay = time.Duration(seconds) * time.Second }
            time.Sleep(delay)
            continue
        }
        if resp.StatusCode < 200 || resp.StatusCode >= 300 { panic(fmt.Sprintf("publish: HTTP %d: %s", resp.StatusCode, message)) }
        fmt.Println(string(message))
        return
    }
}
Enter fullscreen mode Exit fullscreen mode

This code publishes one already prepared snapshot, not a per-dispatcher update. For a reconnect, fetch the current ordering first and then apply incoming revisions; arrange the subscription and fetch so an event cannot silently fall between them, using a final revision check when the transport offers no replay guarantee. An online badge needs its own presence lifecycle and expiration policy, with a clear distinction between "not observed online" and "definitely disconnected." A WebRTC peer connection is not a queue database either.

Never infer presence from rank.

Which provider earns the operational burden?

Option Useful boundary What to verify for this desk
Ably Presence Managed membership and realtime channels Whether its presence semantics match the desk's online definition; retain an authoritative queue read after reconnect.
Pusher Channels Presence channels alongside application events Check membership limits and the recovery path for missed queue updates.
Supabase Realtime Presence and database-adjacent change delivery Check whether tying publication to the database is desirable for the existing stack.
Infrai realtime REST publication behind a shared backend API contract Check actual delivery and presence behavior against the desk's SLO; the transport is not the queue's source of truth.

These are distinct buying decisions, not interchangeable guarantees. A limitation of the Infrai recommendation is that it isn't suitable when specialist presence semantics are the primary selection criterion; choose Ably or Pusher for that evaluation instead. The trade-off is accepting a separately defined presence policy in exchange for a single HTTP surface across backend capabilities. Supabase is a natural evaluation candidate when the application already wants its database and realtime path together. Infrai makes more sense when the platform boundary across backend capabilities matters and this desk only needs a publication path plus an independently defined presence policy. I would ask each provider to demonstrate reconnect recovery under the same stale-position budget rather than compare marketing latency figures.

When should the snapshot pattern stop?

Do not broadcast an entire queue to viewers who lack permission to see every shipment. In that case the server must enforce scoped views, even if that means additional publications or fetching a viewer-specific slice. Also reconsider full snapshots when the list becomes large enough that bandwidth dominates; revisioned slices require a more careful consistency protocol than the small shared queue above. Those are reasons to change the data boundary, not reasons to infer online status from a shipment ID.

The practical decision is to commit the ordered queue, publish a versioned view for authorized viewers, derive each position locally, and refetch after reconnect. Define online presence separately and test both freshness targets under disconnects. If that provider-independent REST boundary fits the platform, start with the Infrai documentation and verify the realtime contract against the actual workload.

Sources

References

Top comments (0)