oxidecomputer / oxidecomputer/console

Handle version mismatches on lazy-loaded asset imports

Open
#1,677 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
228
Forks
22
Avg merge
19h 42m
Merged PRs (30d)
32

Description

@citrus-it reported on the rack after an update that he tried to look at an instance's serial console and got the following error on navigation:

Error
Failed to fetch dynamically imported module: https://oxide.sys.rack2.eng.oxide.computer/assets/Terminal-b80ee2b3.js

It was fine after a refresh. There are two possibilities here, but both are basically the same problem: a version mismatch between the console loaded in the browser and the assets on the server.

  1. He already had the console open before the update, then ran the update, then tried to navigate to the serial console. At that point, the version of the lazy-loaded Terminal.tsx his browser wanted is different from what's on the server (they have hashes in their filenames for cache-busting purposes).
    • A fancy fix for this would be to have a periodic ping to the server, like we talked about in #1616, and the response could include the system version, and if we get a different version from the one we got last, we know we should refresh the page.
  2. There were two Nexus instances with different versions of the console assets because one hadn't finished updating. So you load the console index.html from one Nexus, but then the request for the terminal asset goes to the other one, which doesn't know that hash.
    • This is a hard situation to get out of. Assuming the out-of-sync Nexus instances will eventually catch up with each other, all you can do is wait and refresh. You could also imagine a mechanism that tries to keep requests from a given client going to the same Nexus instance. You probably wouldn't want do that for all API requests, but maybe it could be tolerable for console requests only. But that cure is probably worse than the disease.

Both of these are definitely things that can happen in the real world!

Mitigation/solution

My first thought was that we could catch the error on lazy-load with a .catch() on the React.lazy() call, and refresh the page. But if there's a real problem with the file, you get a refresh loop. I think the better solution is just to land on an error page that says try refreshing. So in practice this ends up being roughly the same thing as #1668. In fact it may be identical, because the error thrown by the promise might bubble up through the <Suspense> tag to be caught by an error boundary.

We may want to show slightly different copy depending on what kind of error it is. If it's this module import error, we can be more confident than usual that a refresh will fix it. On the other hand, "try refreshing" is pretty much always going to be good advice.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Read the error-boundary work referenced in #1668 and trace how React.lazy() and Suspense handle a failed lazy-loaded module import. The change is done when this version-mismatch error reaches an error page with guidance to try refreshing, without creating a refresh loop.

Written by the indexing model from the issue text.

Assessment

Tech stack
react, typescript
Domain
frontend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.