-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Description
Proposal
Better recognize when the session is over
Currently, the client in a Blazor Server app tries to help the server with disposing unneeded circuits by sending a disconnection beacon during the unload
JS event. (After merging #62805 this will be replaced with the pagehide
event.)
This mechanism is not dependable and in many cases - in particular on mobile devices - leads to the server never realizing that the client has abandoned the session and the circuit data does not need to be kept around (in the disconnected cache, later in the serialized state storage).
We want to explore the possibility to improve these scenarios using information about page visibility. The Blazor client would send additional beacon message to the server when the page gets hidden (put into background) or made visible again (put into foreground). The server would use this when deciding what to do with the circuit if it gets disconnected.
Send more dependable beacon
Currently, we use the Navigator.sendBeacon
API to send the disconnection beacon to the server. This method can be blocked by some popular ad-block/anti-tracking browser extensions
(e.g. uBlock Origin).
We should experiment with other APIs (e.g. fetchLater
or even regular fetch
) to see if we can get more dependable delivery of beacon messages. We could also consider dispatching via multiple APIs in parallel ff the message is handled in an idempotent manner on the server.
Motivation
Reasoning behind the visibility-based optimization is as follows:
- The
visibilitychange
event is the only one that fires somewhat reliably on mobile devices, in particular when switching tabs in the browser, switching to another app, or going to the home screen. - In these situations, the tab with the Blazor app (or the entire browser) is often discarded
and no other events are processed. - From the server's point of view, this manifests as such: 1) the server receives the visbility change beacon with the
hidden
state, 2) depending on the timeout settings, the server recognizes at some point that the SignalR connection has disconnected. - Previously, unless we received the disconnect beacon (based on the
unload
/pagehide
event), we would move the disconnected circuit into theDisconnectedCircuits
memory cache, and later into the persistent state storage. This is wasteful for the mobile scenarios described above as circuits from closed/discarded tabs would never be restored anyway.
Risks
- On mobile this change can help significantly. However, on desktop, this does not help much because there the
pagehide
event fires mostly in the same situations as thevisibilitychange
- taking into account only situations where we actually want to dispose the circuit (closing the tab, navigating away, hard refresh, closing the browser). - Inevitably, there is a scenario which we make worse: user switches tabs (but the Blazor app is still loaded and communicates with server), then the device loses network connection. Previously, we would move the circuit into
DisconnectedCircuits
, now we terminate and dispose it (because the server sees the same order of events as e.g. in the mobile app switch scenario) even though the circuit would be eligible for restoration when the device regains network connection and the user foregrounds the Blazor tab. We want to minimize the chance of this happening. - There are also other browser-side optimizations (particularly on desktop) such as background tab freezing or throttling that might lead to the SignalR connection breaking while the page was hidden. In these situations we don't want to dispose the circuits prematurely because they may be restored when the user switches back to the Blazor tab. For this reason, we might want to dispose only circuits for recently hidden tabs as these optimizations typically kick in after some time.
- By adding the visibility change beacon, we are obviously increasing traffic and use some additional server resources for processing the beacon.