UUI icon indicating copy to clipboard operation
UUI copied to clipboard

[APIContext] Automatic app reload on new version release

Open jakobz opened this issue 2 years ago • 0 comments

Description

When an application releases a new version, previous versions of the app continue to work in users' browsers. This can be a problem, as a newer version of apps might rely on a newer version of backend API, which can be incompatible with the previous version. This can cause random errors, and even data-corruption issues. There can also be frontend-only hotfixes, which apps wants to apply ASAP.

As UUI already have low-level API-related features in ApiContext, like error handling, server connection recovery, auth lost, it can be a good idea to incorporate handling of new version releases there as well.

Describe the solution you'd like

There are several ideas described here: https://www.codemzy.com/blog/clients-reload-single-page-application-update

However, approaches in the article above, require tight coupling of frontend and backend builds.

I suggest a simpler method:

  • backend API includes some arbitrary version string in API response, in some pre-agreed header, let's use 'X-Version' header
  • UUI checks the version returned from API calls
    • on the first call, it remembers the version
    • on successive calls, it checks if API version is changed
  • if API version is changed, UUI can reload an app.

This mechanism can be used in two ways:

  1. Backend incorporates its version into build, and send it to frontend. If frontend and backend are in the same repo, and are deployed together, it would work fine. If frontend and backend are in separate repos and deployed separately, this would still reload on backend API updates, but not frontend-only updates. Which can be ok, as API incompatibility issue remains solved.
  2. Backend can send a version of frontend. This can be a simple index.html hash. This is bit more tricky to implement, but would trigger update only when the frontend is updated. It's a common pattern to pack frontend files into a Docker image in NGinx, in this case the version header can be incorporated into NGinx config at build-time.

The suggested approach would break if frontend is updated after the app is loaded, but before the first API call is made. This can be handled by incorporating the app version into the JS bundle. However, the risk is low, and this is too complicated to implement. Let's ignore this risk for now. If we'd need to allow to fix this later, we can accept an 'appVersion' prop for ApiContext on app startup.

There are several options on when to reload the app:

  1. Reload immediately, risking losing some user data
  2. Show modal with a prompt, allowing to postpone update.
  3. Reload immediately if there's no lock in the LockContext. If there is a lock - wait until it's released. This wouldn't work if an app doesn't use default useForm behavior, or the LockContext explicitly.
  4. Reload on the next SPA-redirect. Looks like a good balance, but can be tricky to implement. Most API calls are usually made after SPA redirect, to load page data. It's a good moment to reload, however, it's hard to detect that an API call caused by SPA redirect, and it's safe to reload.

I believe that we can start with 3, improving this approach later if needed.

The proposed approach should also work well, if an app is deployed with downtime. In this case, on an API call (e.g. after navigating to another page), UUI would first show the existing 'server offline' banner. Then, after connection is restored, it would immediately reload to a new version. Let's test this scenario during implementation of this improvement.

jakobz avatar Jun 22 '23 12:06 jakobz