NekR / offline-plugin

Offline plugin (ServiceWorker, AppCache) for webpack (https://webpack.js.org/)
MIT License
4.52k stars 295 forks source link

TypeError: Failed to update a ServiceWorker #400

Open mxstbr opened 6 years ago

mxstbr commented 6 years ago

We're hitting this error a lot in our production app, and we think it might be stopping the ServiceWorker from upgrading to a new version of the app: "TypeError: Failed to update a ServiceWorker: An unknown error occurred when fetching the script. in _promiseRejectionHandler"

There's also some variations to the error message depending on browser and operating system:

It happens on all pages and seemingly on all devices. We have no clue why it happens, how to reproduce it or how to fix it. This is our offline-plugin configuration:

https://github.com/withspectrum/spectrum/blob/alpha/config-overrides.js#L108-L146

Have you seen this error before? Do you have any tips for us on how we can resolve it?

mxstbr commented 6 years ago

Looking at the first and last error messages in that list, it might have something to do with the rate limiting of our hosting provider (Zeit) responding with an error because the ServiceWorker fetches a lot of files in rapid succession when updating its local cache? /cc @matheuss @rauchg

NekR commented 6 years ago

@mxstbr I believe those errors are for the request of the ServiceWorker scripts, not the assets. Browser simply cannot download the script to perform the update or even check if update is needed. If all browsers report the error, then it seems to be a problem of the server.

NekR commented 6 years ago

(or it might be due proxy or weird Wi-Fi somewhere which injects wrong SSL certificates and responds with 500)

NekR commented 6 years ago

That's also the reason why ServiceWorker isn't being auto-removed when it receives bad response, because it not be the response from your server (how is that possible on HTTPS, right?) or your server may return bad response because different issues. Imagine if ServiceWorker was auto-unregistering and you were loosing push subscription because of that 😄That would be terrible.

mxstbr commented 6 years ago

Oh shit I think it is because the ServiceWorker responds with the app shell when requesting /sw.js once it already cached everything! Ughhhhh

NekR commented 6 years ago

That actually can't be true. The ServiveWorker file request doesn't go through ServiceWorker itself, so it won't be forever cached or return weird stuff to the browser.

mxstbr commented 6 years ago

Oh I see 🤔 Hmm... Not sure what could be it then, since requesting https://spectrum.chat/sw.js works perfectly fine (except if you have the app cached, obviously) but we're seeing this error hundreds of times a day. 😕

benawad commented 6 years ago

@mxstbr did you find a solution? I'm experiencing a similar problem. This is my config:

      new OfflinePlugin({
        caches: "all",
        updateStrategy: "all",
        autoUpdate: 1000 * 60 * 2, // 2 min
        ServiceWorker: {
          events: true,
          navigateFallbackURL: "/"
        }
      })
mxstbr commented 6 years ago

Nope, still happening for us and it's very breaking :cry:

NekR commented 6 years ago

Those errors are fine. Browser simply isn't able to fetch ServiceWorker for various reason. Do you experience this errors for 100% requests? How exactly is it breaking? Do you receive lots of comments from users that they can't update?

I guess you monitor the main thread for JS errors and report them to some system. The only SW errors what are reported to the main thread are installation / updating errors. i.e. browser isn't able to fetch the file. That process is fully automatic, is controlled only by the browser and JavaScript doesn't affect it. Several things can affect it, e.g.: the browser, the network (proxy, e.g. in airports) and the server.

Let me translate those errors to human readable format.

"TypeError: Failed to update a ServiceWorker: A bad HTTP response code (500) was received when fetching the script."

This is server error. Whatever happens there -- it shouldn't happen. Maybe it's just down (e.g. changing a deployment on Zeit).

"TypeError: Failed to fetch"

That's the most abstract one. Typically it happens then there is no network connection at all. It simply can't fetch the file.

"AbortError: Failed to update a ServiceWorker: The request to fetch the script was interrupted."

This is the network. Something interrupted the connection. It might be due loosing the network connection or network being changed (it happens all the time in the wild).

"TypeError: Script URL https://spectrum.chat/sw.js fetch resulted in error: An SSL error has occurred and a secure connection to the server cannot be made."

This is a proxy issue. Someone sitting in an airport or on a train and that network injects fake HTTPS certificates (man in the middle).

What you may do here, is catching those errors in your code and trying to reschedule the update again. You may also make sure that your server works correctly and those 500 or other errors do not happen at all.

Unfortunately, there is nothing I can do on the plugin's end to help with this issue.

NekR commented 6 years ago

@GGAlanSmithee Hey! Do you have time to add this to FAQ/Troubleshooting maybe?

GGAlanSmithee commented 6 years ago

@NekR great information, I will add it as soon as I find the time

MerlinMason commented 5 years ago

Hey there, thanks for your work on this it's been really useful for us! We're getting a few of the same errors too, I just wanted to check, when you said...

What you may do here, is catching those errors in your code and trying to reschedule the update again.

Is this the sort of thing you had in mind?

OfflinePluginRuntime.install({
        onUpdateReady: () => {
            try {
                OfflinePluginRuntime.applyUpdate();
            } catch (error) {
                setTimeout(() => {
                    OfflinePluginRuntime.applyUpdate();
                }, 1000 * 60 * 1); // try again in one minute
            }
        },
        ...
    });
crobinson42 commented 5 years ago

I have discovered (at least one of the reasons for this error) is because the browser tab (or PWA) is in the background on a user's mobile device for a long period which has different behavior depending on the device and the browser. For example, chrome will close websocket connections to background tabs after ~5min (don't quote me, ruff estimate) and other connections are limited to a certain time period, ie: if your app has a setInterval to manually poll a service in the case of the websocket being disconnected, some browsers and devices will no allow more frequent than 30 or 45 second requests.