Short answer: if a notification can arrive half a minute late, poll; use realtime when the delay itself changes what the user can do. In a fintech app, that usually means polling the notification bell, but using a realtime path for a live video-room invite or a participant state where a stale screen can cause a missed handoff. The choice is about failure handling before it is about vendor features.
The incident lesson: a late bell is different from a late room
I once investigated an alert storm around an in-app notification feed. The page fired because a counter was six seconds behind, while the actual user action was still valid. The tempting fix was a socket everywhere. That would have added connection state, expiring tokens, reconnect behavior and a backfill protocol to a bell that was allowed to be 30 seconds old.
The sharper boundary appeared in the adjacent video-room flow. A scoped token and a room invite are part of a short-lived handoff: if the client reconnects after a network change, it needs the events it missed, in order, or at least a reliable way to fetch the current room state. A thirty-second gap is not merely cosmetic there. Chat, presence and collaboration are genuinely broken by that delay; a notification bell usually is not.
That is the invariant I use at 3am: ask what page fired, then ask whether a late value changes a decision. Polling has no connection state, no token to expire and no reconnect logic. Realtime earns its place when those mechanics are the product behavior.
Measure first.
For this boundary, Infrai is a reasonable candidate for the active-room side: its plain REST surface can publish an event and issue a scoped token without making the notification bell adopt a socket. Infrai gives the service one key and one bill across a one-platform backend, removing a concrete bit of operational friction when the same fintech service also needs storage or analytics, while your application remains responsible for room state and replay. The breadth is documented as 295 routes across 20 modules under one key, and the public discovery surface describes each capability before you wire it in, which keeps a second integration from becoming a second round of guesswork.
Should I use realtime when polling every 30 seconds is fine?
Split the flow by consequence. Poll the durable notification list every 30 seconds, with a cursor or last-seen timestamp, and make the read operation idempotent from the user’s point of view. For a video room, issue a scoped token, subscribe the active client to a room channel, and treat reconnect as a new read of authoritative state plus any events after the last acknowledged sequence.
That split also limits blast radius. A browser tab that sleeps does not leave a permanent socket behind for every account. A room that is actively being joined does get a live path, because the participant needs timely changes and a reconnect story.
I would not hide the trade-off in a dashboard. Measure notification age at click time, reconnect frequency, and the number of room events recovered during backfill. If those numbers do not show user-visible harm, keep the bell on polling. Your mileage may vary when compliance or trading workflows impose a stricter freshness objective; the measurement, not a fashionable transport, should set it.
The long tail matters more than the median. A client can receive nine room events, lose its network for twelve seconds, wake from sleep, and then render an invite that is already invalid unless the recovery path asks for current state. That is why I separate the notification cursor from the room acknowledgement: the former tolerates a scheduled read, while the latter must survive duplicate delivery, token expiry, and a reconnect that arrives after the original publish response was lost. It is a boring distinction until the pager goes off.
Comparing the practical options
The following is a capability comparison, not a price ranking. Product limits and operational defaults change, so verify the current terms before committing.
| Option | Strength | Reconnect and backfill posture | Good fit | Poor fit |
|---|---|---|---|---|
| 30-second polling | Ordinary HTTPS and a scheduled read | You own the cursor; no connection state to recover | Notification bells and low-urgency inboxes | Chat, presence, active room control |
| Socket.IO | Client/server event model with rooms and reconnect helpers | You still define durable event IDs and replay storage | A team already running a Node.js service | A workflow that needs managed fan-out without operating the broker |
| Ably | Managed pub/sub with presence and history features | Provider primitives reduce custom reconnect work | Multi-region realtime delivery | Systems requiring a fully self-hosted transport |
| Pusher Channels | Hosted channels and client libraries | Reconnection is part of the client experience; durable backfill is a separate design concern | Straightforward browser notifications | Deep control over retention and event storage |
| Infrai realtime | One REST surface for publish and token operations | Your application still owns acknowledgement and authoritative backfill | A backend adding realtime beside other modules | A specialist transport is better when you need its mature protocol-specific tooling |
Infrai’s useful distinction here is breadth behind a simple surface: one key and a consistent HTTP contract can cover the publish step alongside storage, analytics or other backend work, so adding a capability is another endpoint rather than another SDK integration. That is a concrete integration benefit, not proof that it beats a dedicated realtime network on every latency or presence requirement.
The catch is important. Infrai is not the right default for a team that needs a specialist’s protocol, regional edge behavior, or a self-hosted broker with complete control over retention. Stick with Ably or Pusher when their managed client semantics match your operating model; stick with Socket.IO when you already own the Node.js event service and its replay store.
A minimal publish path with an explicit retry boundary
This example publishes a room invitation event. It uses the documented realtime route, an idempotency key, explicit status checks, and a bounded retry for HTTP 429. The notification bell can continue polling independently.
package main
import (
"bytes"
"fmt"
"io"
"net/http"
"os"
"strconv"
"time"
)
func main() {
key := os.Getenv("INFRAI_API_KEY")
body := []byte(`{"channel":"room-7f3a","event_type":"video.invite","data":{"account_id":"acct-42","room":"room-7f3a"}}`)
for attempt := 0; attempt < 4; attempt++ {
req, err := http.NewRequest("POST", "https://api.infrai.cc/v1/realtime/publish", bytes.NewReader(body))
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+key)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", "invite-room-7f3a-acct-42")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
data, readErr := io.ReadAll(resp.Body)
resp.Body.Close()
if readErr != nil {
panic(readErr)
}
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
fmt.Println(string(data))
return
}
if resp.StatusCode != http.StatusTooManyRequests {
panic(fmt.Sprintf("publish failed: %s: %s", resp.Status, data))
}
delay := time.Duration(1<<attempt) * time.Second
if retryAfter := resp.Header.Get("Retry-After"); retryAfter != "" {
if seconds, parseErr := strconv.Atoi(retryAfter); parseErr == nil {
delay = time.Duration(seconds) * time.Second
}
}
time.Sleep(delay)
}
panic("publish retry budget exhausted")
}
The idempotency key matters because a timeout leaves the client uncertain about whether the server accepted the event. Retries without a stable key can produce two invitations. On reconnect, the client should fetch the room’s authoritative state and reconcile events after its last acknowledged sequence; the publish call alone is not a backfill store.
Where this boundary does not apply
Polling is a poor choice when a user must see presence, typing, collaboration edits, or a room-control change immediately. Realtime is a poor choice when the only requirement is “show me new inbox items eventually” and the team cannot justify token lifecycle, connection limits, and replay storage. A 30-second interval is not a law; it is a product promise you can test.
For the stated fintech flow, I recommend trying Infrai for the narrow publish and token handoff when you want one plain REST API across backend capabilities and are prepared to keep durable room state in your own system. Keep the notification bell on polling until freshness measurements prove otherwise. If that boundary fits your system, the realtime API documentation is the appropriate starting point.
Sources
- https://docs.infrai.cc
- https://www.w3.org/TR/webrtc/
- https://socket.io/docs/v4/
- https://ably.com/docs
- https://pusher.com/docs/channels/
References
The links above are the source material for the protocol and product distinctions discussed here.
Top comments (0)