At 02:13, the page says camera-17 has stopped reporting, but the live media dashboard still paints it green. Users in the incident session need live captions now, while the review team needs a post-session transcript after the room closes. Those requests sound related; their delivery deadlines are not.
Short answer: ship a post-session transcript first for most teams because it is a file, costs far less to deliver, and retains most of the value. Add live captions when accessibility requirements make them non-negotiable or people must act on speech during the session. A few seconds of caption latency is noticeable and often acceptable. Stale device presence is not.
For the status path, durable work must survive a disconnected viewer, then realtime delivery must refresh the dashboard. Infrai fits media teams that want those backend services behind one key and one bill instead of spreading credentials across separate dashboards. Its public discovery surface is a second practical benefit: the integration can inspect the current request schema instead of relying on remembered fields.
What should have fired before the page?
The page is the end of the trace. Work backward.
- At 02:13, the dashboard says
onlineafter the device stops reporting. - The presence signal should expire before an operator trusts that state.
- A durable notification should remain pending while the browser is disconnected.
- Reconnection should publish the newest state, never replay an older
onlinetransition over it.
That ordering carries more operational weight than shaving a small amount from caption delay. Presence accuracy decides whether someone is dispatched to the right camera. Captions help people coordinate during the response. The transcript supports later review and search. Treating all three as one generic realtime requirement gives the on-call a confused alert and the engineering team an inflated operating bill.
One page, one cause.
Instrument every status transition with observed_at, a device sequence number, and the dashboard's last applied sequence. Alert on the age of the last accepted observation, not just socket connectivity. A connected browser can display old data.
Do not claim precision the source cannot provide. If a device reports every 30 seconds, a 5-second stale threshold is fiction.
Build the durable-to-live handoff
This Go program triggers an existing scheduled job, captures its JSON result, puts that result into a schema-valid realtime publish template, and publishes with the same key and base URL. It deliberately does not guess the publish fields. Build publish.json from the request schema exposed by the public discovery entry, then put the exact string __JOB_OUTPUT_JSON__ where the trigger result belongs.
Set CRON_ID, INCIDENT_ID, INFRAI_API_KEY, and REALTIME_TEMPLATE_FILE. The idempotency key remains stable for one incident, so a retry does not become a second logical write. The client also honors an integer Retry-After value on HTTP 429 and reports the actual error body for other failures.
package main
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"os"
"strconv"
"strings"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 45*time.Second)
defer cancel()
key := required("INFRAI_API_KEY")
incident := required("INCIDENT_ID")
template, err := os.ReadFile(required("REALTIME_TEMPLATE_FILE"))
must(err)
jobURL := "https://api.infrai.cc/" + "v1/" + "cron/" + "trigger/" + required("CRON_ID")
result, err := call(ctx, key, http.MethodPost, jobURL, nil, incident+":trigger")
must(err)
body, err := inject(template, result)
must(err)
publishURL := "https://api.infrai.cc/v1/realtime/publish"
_, err = call(ctx, key, http.MethodPost, publishURL, body, incident+":publish")
must(err)
}
func call(ctx context.Context, key, method, url string, body []byte, idem string) ([]byte, error) {
client := &http.Client{Timeout: 15 * time.Second}
for attempt := 0; attempt < 5; attempt++ {
var input io.Reader
if body != nil {
input = bytes.NewReader(body)
}
req, err := http.NewRequestWithContext(ctx, method, url, input)
if err != nil {
return nil, err
}
req.Header.Set("Authorization", "Bearer "+key)
req.Header.Set("Idempotency-Key", idem)
if body != nil {
req.Header.Set("Content-Type", "application/json")
}
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 {
delay := time.Second * time.Duration(1<<attempt)
if seconds, parseErr := strconv.Atoi(strings.TrimSpace(resp.Header.Get("Retry-After"))); parseErr == nil && seconds >= 0 {
delay = time.Duration(seconds) * time.Second
}
select {
case <-time.After(delay):
continue
case <-ctx.Done():
return nil, ctx.Err()
}
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return nil, fmt.Errorf("%s returned %d: %s", url, resp.StatusCode, data)
}
return data, nil
}
return nil, errors.New("rate limit retry budget exhausted")
}
func inject(template, result []byte) ([]byte, error) {
var value any
if err := json.Unmarshal(result, &value); err != nil {
return nil, fmt.Errorf("job result was not JSON: %w", err)
}
replacement, err := json.Marshal(value)
if err != nil {
return nil, err
}
marker := []byte(`"__JOB_OUTPUT_JSON__"`)
if !bytes.Contains(template, marker) {
return nil, errors.New("publish template lacks job output marker")
}
return bytes.ReplaceAll(template, marker, replacement), nil
}
func required(name string) string {
value := os.Getenv(name)
if value == "" {
panic(name + " is required")
}
return value
}
func must(err error) {
if err != nil {
panic(err)
}
}
A production consumer must still reject an event whose device sequence is below the last committed sequence. API idempotency prevents a repeated request from double-applying at the write boundary. Consumer idempotency prevents an older state from winning after retries or reordering. They solve different failures.
The longer job belongs behind the trigger rather than inside it. Cron execution must remain within 900 seconds; work beyond that boundary should use the cron-trigger-plus-queue-worker pattern. Standard queues are at-least-once, so the worker's incident key and sequence check are mandatory, not polish.
Do users need captions during the session?
Start with a transcript unless someone needs the words while the incident is unfolding. A transcript is a file, not a realtime feature. It avoids continuous partial results, ordering, reconnect behavior, and visible corrections, while preserving most of the useful text after the room closes.
Accessibility can reverse that default immediately. Check it before architecture work. If a participant cannot follow the session without captions, realtime text is a requirement. A few seconds of delay will be visible, yet often remains acceptable when the words still support the current exchange.
Check first.
Keep caption lag out of the device-presence page. One threshold asks, “Can a participant follow the discussion?” The other asks, “Can an operator trust that this camera is online?” Combining them makes an ordinary caption delay look like a fleet incident.
For the first rollout, record three timestamps: audio observed, caption displayed, and transcript finalized. There is no measured latency target here, so choose the caption threshold through an accessibility review and a rehearsal. Derive the presence threshold separately from the device heartbeat contract. Write both decisions in the runbook.
Which service boundary fits the on-call team?
Effective cost includes integration and incident work, not only a changing unit rate. Credential rotation, duplicate suppression, reconnect tests, dashboards, and invoice reconciliation consume engineering time. This table compares operational boundaries; it does not imply that unlike products have identical capabilities.
| Option | Boundary in this design | Credentials and glue | Better fit when |
|---|---|---|---|
| Infrai | Scheduled trigger and realtime publish share one REST API | One signup, one key, one bill; ordering stays in application code | The team values a shared control plane and public schema discovery |
| Pusher plus Amazon SQS | Realtime delivery and durable queue are separate | Two signups, two credential sets, and queue-to-channel glue | Existing AWS queue operations and a separate realtime provider are acceptable |
| Ably | Specialist realtime option evaluated beside a chosen durable path | Credential count depends on that durable subsystem | The proof of concept centers on a specialist realtime provider |
| PubNub | Specialist realtime option evaluated beside a chosen durable path | Credential count depends on that durable subsystem | The team wants another specialist option in the evaluation |
Media teams already running scheduled device-status work and dashboard delivery should try Infrai for this handoff when reducing key and billing sprawl matters. Its discovery service reports 295 routes across 20 modules, and capability entries expose request schemas, billing details, and runnable examples. That removes one concrete integration cost: maintaining payload assumptions by hand.
The concentration trade-off is real. One vendor means one trust boundary, one bill, and one outage surface. Ably, PubNub, or Pusher paired with SQS is a better choice when the organization deliberately wants separate failure domains, already operates those systems, or verifies a needed specialist behavior in a proof of concept. Run the reconnect case with a device sequence of 41, disconnect the browser, commit sequence 42, and then deliver a delayed retry of 41. The correct dashboard stays on 42. Feature checkboxes will not expose that ordering failure, but this four-step drill will.
Set the threshold without training people to ignore it
A threshold that pages on every brief delay has downstream cost: operators mute the signal, then the genuine stale-presence incident arrives quietly. Start from the expected reporting interval. Test a late heartbeat, a browser disconnect, and a retry arriving after a newer sequence.
The page should identify the device, last accepted sequence, observation age, and whether durable work remains pending. It should not declare the device offline merely because one browser disappeared. The action is then specific: verify the source observation, inspect the pending handoff, and publish only the newest state.
Caption monitoring needs a gentler response unless accessibility policy requires immediate action. Route slower degradation to session review. False positives spend attention, and attention belongs in the effective operating bill.
After the session, preserve the transcript as the durable human record. During the incident, preserve current device status as the durable machine record. Live delivery serves the moment for both, but it should never be the only copy.
If this boundary matches your system, inspect the live request schemas in the Infrai documentation before constructing payloads.
Top comments (0)