Skip to content

Release v20.60.2

Choose a tag to compare

@github-actions github-actions released this 21 Jul 11:10
1c664c4

Summary

Observable query connections were being torn down and rebuilt every few minutes on any app with live data. Each teardown re-subscribed every observable query and re-delivered every snapshot, which shows up in the UI as the whole page flickering while you work.

The cause was the two ends of the keep-alive contract disagreeing. The server only sent a keep-alive when a full interval had passed since its last message, but checked that on a fixed interval grid — so a data message landing mid-interval pushed the next keep-alive out by nearly another full interval. The SSE client, which treats silence as a dead connection, gave up before that keep-alive arrived and reconnected a connection the server considered perfectly healthy. The busier the connection, the more often it happened.

This fixes the reconnects, and separately makes the re-delivered snapshot that follows any reconnect cheap: the client now reconciles it against what it already holds, so only the items that actually changed re-render.

Fixed

  • Observable query connections no longer reconnect spuriously while data is flowing. The server now guarantees a message at least once per keep-alive interval instead of allowing gaps of up to twice the interval, so the SSE client stops tearing down healthy connections, re-subscribing every query and re-delivering every snapshot — which surfaced as UI flicker during normal use.
  • Re-delivering a snapshot no longer re-renders everything. Incoming payloads are reconciled against the data already held, so items that did not change keep their object identity and only the items that actually changed re-render. An identical snapshot produces no update at all.
  • Setting Query.KeepAliveInterval to a longer value no longer causes the SSE client to reconnect in a loop. The client now derives its idle threshold from the interval the server advertises rather than assuming the default.
  • Disabling keep-alive by setting Query.KeepAliveInterval to zero or a negative value no longer leaves the SSE client reconnecting forever waiting for pings that were never going to come.

Added

  • reconcileQueryData in @cratis/arc/queries, which reconciles a freshly received payload against the previous one and preserves references for everything that did not change. Items are matched by their conventional id, falling back to position.

Changed

  • The Connected message on the observable query hub now carries the server's keep-alive interval so clients can align their idle detection with it.
  • ObservableQueryHubMessage.CreateConnected now takes the keep-alive interval alongside the connection identifier. This type is the hub's wire protocol and is not constructed by application code, so no application-level change is needed.