feat(host): a live read polls while Realtime fails it
This is the second of two stacked PRs for "a live read polls while Realtime fails". It stacks on #4167, which lets the service answer a live read's rows inline.
What changes
All the switching lives in liveRows in packages/host/src/live-follow.ts. Any area that reads through liveRows gets it; on main that is the board.
Switching to polling. liveRows starts polling when any of these happens:
- a subscription goes to
error; - Realtime's client doesn't load;
- a renewal is refused;
- the service answers a seal at the poll address.
While polling, it asks the service for the read's rows inline every 3 s (LIVE_POLL_EVERY) and feeds them to the same consumer. It skips a poll whose rows haven't changed.
Switching back. While polling, it subscribes to Realtime again every 15 s (RESUBSCRIBE_EVERY). Realtime's first delivery stops the polling.
Logging. Each switch is logged: a warning with the reason and Realtime's error code when polling starts, and an info line when Realtime is back. The sealed query is never logged.
Failure. liveRows now fails only when the read is gone, as before.
The board's part. The board gains one dependency, poll, which calls client.boardLive(taskId, true). compose-tasks shares the existing "gone" mapping between sealing and polling.
Tests
liveRows: a subscription that goes toerrorswitches to polling, and the polled rows are delivered. Unchanged polls deliver nothing new. Realtime delivering again stops the polling. The three "fails where…" tests are replaced, since those cases now poll instead of failing.- Board: through a simulated outage the board keeps moving on polled rows, and polling stops once Realtime delivers again.
compose-tasks: the board test now expects the resubscribe after a stop to happen on the 15 s beat.
Made with Luke