Behavior of web apps when user leaves browser open

Hello,

I am using Retool Cloud. Am I correct that if a user leaves the browser window open to my app, and I push a new release of my app, the user will not pick up the changes unless they reload the page? Assuming that is correct:

  • How long will the user session stay open before it does something that forces a page reload? I am using Retool Cloud.
  • Is there any way to notify these users who keep the browser window open that a new version of the app has been released and they should reload the page?

Thank you!
-Frank

1 Like

You are correct.

I have had apps open for some days before Retool logs me out.

I am not aware of any way to notify user of changes. There may be a few ways way to hack this together.

:wave: Hey all,

Stumbled on the same issue some time ago. We had dashboards running 24/7 on floors with no user access (only screen) or seldom user interaction so their versions always got stuck and had to be manually refreshed.

The most obvious path was to create a "ping" table and set the app_uuid and version_number I wanted to lock in and all open apps would poll that every 10 minutes. If the specified version was higher then the current version I would issue a page refresh.

The problem was, multiple tabs, multiple machines, same user. I needed a simple heuristic for grouping devices by browser and platform. That would catch at least most of the cases.

const browserName = navigator.userAgent.match(/(Firefox|Chrome|Safari|Opera|MSIE|Trident|Edge)\/?\s*([\d\.]+)/i)?.[1].toLowerCase() || '';
const platformName = navigator.userAgent.match(/(Macintosh|Windows|Linux)/i)?.[0].toLowerCase() || '';
return `${platformName}_${browserName}`.replace(/\s/g, '');

Add the tables:

  • marco
    • app_uuid
    • app_version
  • polo
    • marco_id
    • user_email
    • device_fingerprint

The periodically executed marco query which fetches new "pings" and evaluates if a refresh is necessary.

SELECT
  m.id AS marco_id,
  m.app_version,
  m.app_uuid,
  (
    (LPAD(REPLACE(m.app_version, '.', ''), 3, '0')::INT > LPAD(REPLACE({{app_version_simulator.value}}, '.', ''), 3, '0')::INT)
    AND p.id IS NULL
  )AS should_reload,
  LPAD(REPLACE(m.app_version, '.', ''), 3, '0')::INT AS lh_vsum,
  LPAD(REPLACE({{app_version_simulator.value}}, '.', ''), 3, '0')::INT AS app_vsum,
  p.id AS polo_id,
  p.user_email,
  p.device_fingerprint
FROM
  marcos AS m
  LEFT JOIN polos AS p ON (
    p.marco_id = m.id
    AND (
      p.user_email = {{current_user.email}}
      OR p.user_email IS NULL
    )
    AND (
      p.device_fingerprint = {{device_fingerprint.value}}
      OR p.device_fingerprint IS NULL
    )
  )
WHERE
  m.app_uuid = {{retoolContext.appUuid}}
ORDER BY
  lh_vsum DESC
LIMIT
  1

The logic of the above query boils down to these two fields which are included in the response:

{
  "app_version": "0.1.1",
  "should_reload": true,
}

A success handler executes the "polo" query (if the current app version is less then the marco app version) which just adds a record against the "marco" record noting down the user_email and device_fingerprint. Once saved:

utils.showNotification({
  title: "Refreshing the app in 10 seconds",
})

await new Promise(resolve => setTimeout(resolve, 10000))

utils.openUrl(urlparams.href, {newTab: false, forceReload: true})

That's a tl;dr of how I implemented it. I can create a demo app if anyone is interested :v:

2 Likes

Thank you for this solution!

I had a similar idea where you would have a catalog table that held the latest app_version and the app would periodically check in to see if it's version was current. If not then alert the user to the need for a reload (or just force a reload.)

The dev has to remember to set the newest version in the catalog when creating a new release.

Please do create a demo app. I'm interested.