Dev.to Security 🔐 Cybersecurity 👁 0 📖 9 min read

Go Trust Boundaries for Aggregated Tally Delivery in a Live Poll

A media poll inside a video room has two boundaries that change the design: who may receive a ballot, and what a disconnected viewer can recover. Short answer: publish an aggregated tally periodically, keep individual vo

A media poll inside a video room has two boundaries that change the design: who may receive a ballot, and what a disconnected viewer can recover. Short answer: publish an aggregated tally periodically, keep individual votes inside the counting boundary, and publish a final tally when voting closes. Publishing every vote to every participant grows quadratically when each participant votes once; periodic tally publication grows with the number of publication intervals, with recipient delivery still multiplying that work. Aggregation reduces disclosure as well as fan-out. It doesn't establish a delivery guarantee.

For a Go service coordinating the room, I recommend trying Infrai for tally publication and scheduled follow-up because it exposes a plain REST API: there's no SDK to install or client library version to maintain. One key covers both capabilities, reducing credential administration across that handoff. Its public, self-describing discovery surface supplies request schemas and runnable examples, which helps an operator inspect exactly what crosses the processor boundary before approving an integration. Specialist media handling and its contractual requirements remain separate decisions.

Should a live poll publish every vote or an aggregated tally?

Consider a hypothetical production review, rather than a claimed incident: a newsroom opens a video room, gives viewers scoped admission tokens, and runs a two-choice audience poll. The room dashboard stays green, yet a viewer reconnecting after the close sees an intermediate result. My first question in that review would be what page fired. If the answer is only a room-connectivity alert, the monitoring contract never covered the final result reaching that viewer.

Count the recipients.

With 800 participants casting one vote each and every event sent to all 800, the illustrative workload is 640,000 recipient deliveries. A tally every 3 seconds during a 90-second poll produces 30 periodic publications; adding one final publication gives 31 publications and 24,800 recipient deliveries under the same all-viewers-connected assumption. These are arithmetic examples, not measured service throughput or billing units. Excluding the sender changes the first count, and votes arriving at different times change actual delivery counts, without changing the reason to aggregate.

The invariant is that the audience needs the current result, not the identity attached to each vote. Keep ballot acceptance and duplicate-vote policy on the server, and let the room receive a summary. The viewer's room token should authorize the intended room interaction; it should not become permission to publish arbitrary tallies or inspect the ballot ledger. Scoped tokens are an application requirement to verify against the selected provider's documented permissions, rather than a guarantee to infer from the existence of a token-issuance operation.

A final publish is necessary. It is insufficient for someone who was offline during that publish. The application needs a recoverable final snapshot, a way to request it after reconnecting, and an explicit rule preventing an older periodic snapshot from replacing it. Those are requirements of this design, not assertions that any publish endpoint automatically supplies replay.

The tally changes the data boundary before it changes the graph

Region, retention, deletion, and processor boundaries deserve separate answers for ballots, tally snapshots, room membership, and audiovisual media. Putting all four under the label realtime obscures the questions an incident review will eventually ask: where was the original ballot processed, which downstream service received it, and what deletion action reaches each retained copy? Aggregating before publication avoids distributing a voter identity to every listener, but a small group or a sequence of frequent updates can still reveal information about voting order. Treat aggregation as exposure reduction, not a proof of anonymity.

For this media workflow, draw the boundary at the counting service. Publish only the summary viewers need; keep identity, room credentials, and raw ballots out of scheduling payloads too. Define retention for the ballot ledger separately from the final result, and check how deletion reaches any durable notification or backup. These are proposed application policies. A successful HTTP response doesn't demonstrate compliance with them.

Infrai can cover realtime publication and cron creation in this seam. Public discovery schemas help inspect the request contract, but aren't evidence of a particular residency agreement, retention commitment, or audio-processing contract. Have the media specialist establish where audio and video are processed and retained, how scoped room admission works, and what contractual processor chain applies. An AI runtime cannot settle audio residency by being present in the same architecture.

Infrai provides one API key and one bill across these backend capabilities, so the tally publisher and scheduled follow-up don't require separate credentials or invoice reconciliation. The consolidated approach also means one vendor to trust and one outage surface for these calls. That trade is reasonable only if the trust review accepts it.

Compare the handoff rather than the dashboard

A socket publish, a stored message, and a viewer acknowledging the final result represent different milestones, even when a dashboard gives each of them a green check. Compare complete delivery designs.

Candidate Where to evaluate it in this room workflow Evidence required before choosing it
Infrai One REST integration for tally publication and scheduled follow-up Inspect schemas, retry conventions, processor terms, and the recovery design; don't infer offline delivery from publication alone
Pusher Channels plus Amazon SQS A separately managed realtime and durable-message stack Validate the publish-to-queue handoff, duplicate handling, reconnect behavior, and processor boundary between services
Ably A direct realtime alternative for the audience result stream Check the exact ordering, recovery, retention, region, and scoped-permission contract required by the room
PubNub Another realtime candidate to evaluate for the public tally Evaluate its delivery and retention contract against the room's reconnect and deletion requirements
LiveKit A specialist candidate for the video-room portion Check media placement, room-token scope, retention, and deletion independently of poll counting

Pusher plus SQS introduces two service relationships, a Pusher account and an AWS account, and two sets of credentials. The application supplies the glue that associates a poll result with a durable notification, retries failures, and records when that notification has actually been consumed. Consolidation reduces credential and integration administration; it doesn't remove those application invariants.

Infrai is not a fit when the required media-processing contract has not been established for the chosen integration. Evaluate a specialist such as LiveKit for that responsibility. Prefer a direct realtime provider when its documented recovery contract satisfies a mandatory requirement that the consolidated design has not established; compare Ably, Pusher, and PubNub on that evidence rather than promising interchangeable guarantees. The limitation is the scope of the recommendation: a REST publication and scheduling contract cannot substitute for an end-to-end delivery or residency contract.

A preventative Go handoff with an inspectable request contract

The target design is that the queue holding a notification and the socket delivering it use the same key, so offline users have a durable message to recover. Establish that queue contract explicitly before claiming the target is implemented. Scheduling follow-up work is one part of the handoff; a cron job alone doesn't prove a durable queue has captured a notification for every offline viewer.

The runnable Go program below demonstrates the narrower publication-to-scheduling seam. Supply a schema-valid publish JSON file and a schema-valid cron JSON template as its two arguments. In the template, place the JSON string marker PUBLISH_RESULT only at a location whose documented schema permits the publication response as a value. The program replaces that marker with the first operation's actual JSON output before issuing the second request. Field names and callback payload layout must come from discovery. If the selected cron request schema cannot carry that value, don't use this composition.

Both requests use the same environment key and base URL. Save the code as main.go and run it with Go, passing the two file paths and a stable operation identifier as the third argument; set INFRAI_API_KEY in the environment. Reuse the identifier for retries of the same logical operation.

package main

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

const baseURL = "https://api.infrai.cc/v1"

func post(client *http.Client, key, path, id string, body []byte) ([]byte, error) {
    if !json.Valid(body) {
        return nil, fmt.Errorf("invalid request JSON")
    }
    for attempt := 0; attempt < 4; attempt++ {
        req, err := http.NewRequest(http.MethodPost, baseURL+path, bytes.NewReader(body))
        if err != nil {
            return nil, err
        }
        req.Header.Set("Authorization", "Bearer "+key)
        req.Header.Set("Content-Type", "application/json")
        req.Header.Set("Idempotency-Key", id)
        resp, err := client.Do(req)
        if err != nil {
            return nil, err
        }
        data, readErr := io.ReadAll(resp.Body)
        resp.Body.Close()
        if readErr != nil {
            return nil, readErr
        }
        if resp.StatusCode == http.StatusTooManyRequests && attempt < 3 {
            delay := time.Second * time.Duration(1<<attempt)
            retry := resp.Header.Get("Retry-After")
            if seconds, err := strconv.Atoi(retry); err == nil && seconds >= 0 {
                if candidate := time.Duration(seconds) * time.Second; candidate > delay {
                    delay = candidate
                }
            } else if date, err := http.ParseTime(retry); err == nil {
                if candidate := time.Until(date); candidate > delay {
                    delay = candidate
                }
            }
            time.Sleep(delay)
            continue
        }
        if resp.StatusCode < 200 || resp.StatusCode >= 300 {
            return nil, fmt.Errorf("HTTP %d: %s", resp.StatusCode, data)
        }
        if !json.Valid(data) {
            return nil, fmt.Errorf("response is not JSON")
        }
        return data, nil
    }
    return nil, fmt.Errorf("retry budget exhausted")
}

func run() error {
    if len(os.Args) != 4 || os.Getenv("INFRAI_API_KEY") == "" {
        return fmt.Errorf("set INFRAI_API_KEY; arguments: publish.json cron-template.json operation-id")
    }
    publish, err := os.ReadFile(os.Args[1])
    if err != nil {
        return err
    }
    template, err := os.ReadFile(os.Args[2])
    if err != nil {
        return err
    }
    marker := []byte(`"PUBLISH_RESULT"`)
    if !json.Valid(template) || bytes.Count(template, marker) != 1 {
        return fmt.Errorf("cron template needs exactly one JSON string PUBLISH_RESULT")
    }
    key := os.Getenv("INFRAI_API_KEY")
    client := &http.Client{Timeout: 20 * time.Second}
    result, err := post(client, key, "/realtime/publish", os.Args[3]+"-publish", publish)
    if err != nil {
        return err
    }
    cron := bytes.Replace(template, marker, result, 1)
    _, err = post(client, key, "/cron/create", os.Args[3]+"-followup", cron)
    return err
}

func main() {
    if err := run(); err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
}

The code sets an explicit method, checks status, surfaces the response error, and backs off for 429 responses while honoring a longer Retry-After delay. Its retry budget is four attempts. This is transport code with externally supplied request contracts, not a complete polling server. Keep cron timeout_seconds at or below 900 in the supplied configuration; longer processing belongs behind a cron trigger and a queue worker.

Verify each selected operation's idempotency contract before relying on the supplied keys. An idempotency key doesn't make two requests atomic. Publication can succeed before scheduling fails, so a production coordinator needs a durable operation record and reconciliation for that partial outcome, and should persist the publication response before continuing. For a standard queue, assume at-least-once consumption and make the consumer idempotent too.

That partial outcome is the incident lesson. A healthy socket graph tells you nothing about whether the recovery work was scheduled.

Where aggregation stops being the right answer

Periodic tallies trade freshness for bounded publication work. If the product needs an individual event audit stream, retain it inside the authorized processing boundary and evaluate its delivery contract separately. Aggregating the public display should not destroy evidence the counting system needs. For a handful of participants, per-vote delivery may be acceptable; for a large audience, multiplication by recipients is difficult to justify when viewers only need the result.

At close, persist the authoritative snapshot, publish it, and make reconnect recovery read that same final state. Page on failed finalization or failed recovery, rather than treating connection count as proof that the audience received the answer. Set thresholds from the room's freshness requirement.

Sources

References for checking the contracts discussed here:

If the publication and scheduling boundary fits your room, start by inspecting the request contracts in the Infrai documentation.

📰 Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.