Workbox: Handling of quota exceeded errors in workbox-precaching

Created on 14 Feb 2018  路  8Comments  路  Source: GoogleChrome/workbox

Library Affected:
workbox-precaching

This is closely related to https://github.com/GoogleChrome/workbox/issues/1308, but the exact analog is https://github.com/GoogleChromeLabs/sw-precache/issues/345

Let's leave runtime caching aside for this issue, and assume that there's a web app instance that has revision N of their assets precached. The web app is updated and deployed, and now there's an attempt to download and cache a few of the new/updated assets that make up revision N+1. workbox-precaching does this in the install handler, and will fail installation if any of the individual cache.put() operations fail. (Since all the assets from revision N are still cached at this point, it's not too hard to imagine scenarios in which caching the new assets brings you over quota.)

From the point of view of the web page clients, there are events fired on the associated service worker registration showing the service worker progressing from the installing state to the redundant state. Unless (somehow) quota is freed up at some point, that installing -> redundant transition will happen indefinitely, leaving the user stuck revision N of all the precached assets indefinitely.

We should do something to help developers out here. What about a pattern like:

if ('serviceWorker' in navigator) {
  window.addEventListener('load', function() {
    navigator.serviceWorker.register('/sw.js').then(function(registration) {
      registration.addEventListener('updatefound', function() {
        var newWorker = registration.installing;
        newWorker.addEventListener('statechange', function() {
          if (newWorker.state === 'redundant') {
            if ('storage' in navigator && 'estimate' in navigator.storage) {
              navigator.storage.estimate().then(function(results) {
                var percentUsed = (results.usage / results.quota) * 100;
                // Let's assume that if we're using 95% of our quota, then this failure
                // was due to quota exceeded errors.
                // TODO: Hardcoding a threshold stinks.
                if (percentUsed >= 0.95) {
                  // Get rid of the existing SW so that we're not stuck
                  // with the previously cached content.
                  registration.unregister();

                  // Let's assume that we have some way of doing this without inadvertantly
                  // blowing away storage being used on the origin by something other than
                  // our service worker.
                  // I don't think that the Clear-Site-Data: header helps here, unfortunately.
                  deleteAllCachesAndIBD();
                }
              });
            } else {
              // What about browsers that don't support navigator.storage.estimate()?
              // There's no way of guessing why the service worker is redundant.
            }
          }
        });
      });
    });
  });
}

and then encapsulate all that logic in the hypothetical new module described in https://github.com/GoogleChrome/workbox/issues/1129?

workbox-precaching

All 8 comments

Thinking out load some more: we might be able to address this inside of the workbox-precaching install handler, by detecting cache.put() quota errors there, and using it as a signal to unregister the current service worker and clear all caches.

That would have the benefit of not requiring developers to change the way they register their service workers, and we would more context about which caches/IDB entries need to be deleted if the cleanup happened inside of our service worker.

  1. (Self Service) We could clear the runtime cache and retry. If still fails, clear cache and unregister the service worker. This would fallback to the network and sw would start failing on install as normal.
  2. (Dev Option) We offer a cb function and on failing precache, developer can do anything they want (including message page - clear cache - clear something else, .....)
  3. Default to self service and dev cb results in replacing default behaviour

@jeffposnick In the case of Safari 11.1, it doesn't support the navigator.storage API atm. What are some of the other possibilities that will fall in the newWorker.state === 'redundant' statement being true?

I'm trying to tackle this problem in general regardless of the browser. The plan is to delete all the known caches generated by our service worker.

Would like to see a solution for this!

@tgangso Relevant pull request for a solution https://github.com/GoogleChrome/workbox/pull/1505

Very interesting, thanks @raejin

@jeffposnick Since we've updated from Workbox 2 to 3, we have Quota exceeded errors when the SW is updating, which makes the update sometimes fail.
I've used the purgeOnQuotaError option on all runtime caching but it doesn't solve the problem, as indeed you write in #1505 :

If you're precaching a massive amount of data, but not runtime caching much, this PR is not likely to help.

What are the solutions ? In v2 it worked fine, maybe because there was no -temp cache during the SW installation ?

There's not a specific solution in place for Workbox v3.

You'd have to trim down the amount/size of URLs that you're precaching.

Coming up with an automated solution is going to require more thought, and is not something that we've been able to address yet.

Was this page helpful?
0 / 5 - 0 ratings