rstudio / shiny-server

Host Shiny applications over the web.
https://rstudio.com/shiny/server
Other
712 stars 291 forks source link

RobustSockJS connectivity issues caused by high client execution latency #522

Open jcheng5 opened 2 years ago

jcheng5 commented 2 years ago

Using the attached demo app:

client-hang.zip

Load it into SSOS or SSP, with reconnect on;. Use Ctrl+Alt+Shift+A in the browser to turn off all transports except xhr-polling, then reload.

Causing the app to hang for 10 seconds results in "RobustSockJS collision" messages. Hanging for 48 seconds results in "Discard position id too big" messages, and disconnection.

This demonstrates that SockJS, and by extension we, are not robust to the client's main thread being blocked for many seconds at a time. This in and of itself might not be that big of a problem, since we need to give up on the client at some point; but it's a problem right now because it's not at all clear to the app author or admin what they're doing wrong.

jcheng5 commented 2 years ago

Here's a handy chunk of code that detects slow ticks and logs errors to the console.

function warnOnSlowTick() {
  let lastTick = new Date().getTime();
  function onTick() {
    let newTick = new Date().getTime();
    if (newTick - lastTick >= 2000) {
      console.error(`Slow tick detected: ${((newTick - lastTick - 10) / 1000)} sec`);
    }
    lastTick = newTick;
    setTimeout(onTick, 10);
  }
  onTick();
}
warnOnSlowTick();
daattali commented 1 year ago

Does anyone have any tips on making the server more robust to situations where the client is very high latency?

jcheng5 commented 1 year ago

You do mean latency in the “slow tick” sense, not a slow network sense, right? If so: this might be stating the (too-)obvious but removing the latency is pretty important from a user experience perspective. For however long the slow tick takes, the user is not able to interact with the web page at all.

We’ve mostly seen these cases with selectize (especially) and DT, where the app author wasn’t using server side mode and switching to server side mode fixed it. What is your client doing that is taking so long?