Core Concepts

ActivityBus

Reconnecting after time offline kicks off two things that both want to bring your cache up to date: a delta catch-up stream, and a routine freshness check. Left uncoordinated, the freshness check can decide data is stale and re-fetch it over HTTP at the exact moment the delta stream is already delivering it. ActivityBus is what keeps those two from racing each other.

Why a fixed wait isn't a safe way to avoid this

The obvious fix is to make the freshness check simply wait a while after reconnect before deciding anything is stale — give the delta stream a head start. The problem is that any fixed wait is a guess about how long catch-up will take, and a guess that's wrong in either direction causes a real problem. Too short, and the freshness check fires its own network refetch while the delta stream is still mid-delivery, racing against data that's actively being written. Too long, and a channel with genuinely stale data — because its own catch-up stream stalled, or the channel simply had nothing to deliver — sits stale for far longer than necessary before anything corrects it.

ActivityBus replaces the guess with an actual signal: rather than waiting a fixed amount of time, the freshness check waits on real information about whether catch-up is still in progress, and proceeds the moment that information says it's done — not a moment sooner or later than the data itself justifies.

1

A channel is either catching up or it isn't

The moment a reconnect begins, every channel involved is marked as being in catch-up — before the connection even finishes opening. That flag doesn't expire on a timer; it's cleared only when the channel's own catch-up stream actually reports completion. This matters because it means classification never depends on how long the server happens to take. A backend that takes one second to start streaming and one that takes a full minute are treated identically correctly — the channel simply stays marked as catching up for as long as it actually is, however long that turns out to be.
2

Completion is detected, not timed

A channel is considered finished catching up either when its backend explicitly says so, or — for backends that don't send an explicit completion signal — when a short quiet period passes with nothing new arriving for it. Either way, the freshness check downstream never has to know which mechanism fired; it only ever asks a single question: is this channel still busy, or has it settled?
Completion detection is silence-based, not duration-based

The signal that a channel has finished catching up isn't a fixed duration — it's silence. A channel is considered settled once a short window passes with no further catch-up events for it. This is deliberately generous by default, to comfortably cover slower query execution, intentional pacing between batches, and ordinary gaps on a weak connection, and it's tunable per adapter for a backend with unusually fast or unusually slow delivery characteristics.

3

A minimum wait, then a hard ceiling

When the freshness check finds channels that look stale right after a reconnect, it doesn't fire a refetch immediately, and it doesn't wait forever either. It holds for a minimum window to give the connection a fair chance to finish handshaking and begin delivering, then keeps polling until every stale channel reports it has settled — capped by an absolute ceiling that fires regardless of what's still in progress, so a genuinely stuck stream can never hold the freshness check hostage indefinitely.
The full timing model

The full window, in order: for the first 20 seconds after a reconnect, Flux always keeps waiting, even if nothing looks like it's syncing yet — the connection may simply still be handshaking. Between 20 and 60 seconds, it keeps polling and exits the moment every stale channel reports it has settled. At 60 seconds, it stops waiting unconditionally, regardless of what's still in progress, and treats anything still stale at that point as a signal that something upstream may be stuck.

4

What happens once the wait ends

After the wait exits — whether because everything settled naturally or because the ceiling fired — the freshness check looks again. Channels that received live updates during the wait already have fresh data and need nothing further; only channels that genuinely received nothing the whole time proceed to a network refetch. In the common case, that second look finds nothing left to do at all. In the rare case where a stream really did stall, the refetch acts as the correct fallback rather than the default first move.
None of this requires configuration in the common case — it's active automatically the moment a realtime adapter is in use. Apps without a realtime adapter at all skip this coordination entirely and fall back to a plain freshness check with no catch-up stream to wait on in the first place, since there's nothing to race against.

ActivityBus is what the delta stream described in core-concepts/sync-anchors is being coordinated against. For the storage side of what "fresh" and "stale" actually mean, see core-concepts/5-layer-stack.