Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add helper method to cleanup cache + expiration data in IDB #1365

Closed
jeffposnick opened this issue Mar 15, 2018 · 7 comments · Fixed by #1500
Closed

Add helper method to cleanup cache + expiration data in IDB #1365

jeffposnick opened this issue Mar 15, 2018 · 7 comments · Fixed by #1500

Comments

@jeffposnick
Copy link
Contributor

Library Affected:
workbox-cache-expiration

Issue or Feature Request Description:
Extracting a feature request from #1354 (comment), @josephliccini and I write:

One thing that I'm not sure about is how well the current workbox-cache-expiration code will behave if you do an "out of band" caches.delete() call to remove a specific runtime cache without also deleting the IDB entries corresponding to its expiration, and then later on recreate the same runtime cache. I'd imagine that it could lead to some confusion—@gauntface?

Maybe the solution there is to expose a workbox.expiration.deleteCache() method that took in a cache name and did both the Cache Storage API deletion as well as the IDB cleanup in one step.

Yes (regarding your response to 5.) this is basically how we've implemented /logout today, and the next step is to go to IDB and clear those out too. I would love a deleteCache() method that does IDB and Cache deletion for a workbox cache 👍

@gauntface
Copy link

This all sounds like a good idea to me.

@josephliccini
Copy link
Contributor

This is how I achieved it: (Note I am on Workbox 2.1.3)

const scope = self.registration.scope;

const cacheKeys = await self.caches.keys()
const workboxPrecachedAssetsCacheKeyRegExp = new RegExp(`^${cacheId}-workbox-precaching-revisioned`);

const runtimeCacheData = cacheKeys.filter(key => !workboxPrecachedAssetsCacheKeyRegExp.test(key));

await Promise.all(runtimeCacheData.map(cacheKey => caches.delete(cacheKey)));

const idbDeletePromises = Promise.all(runtimeCacheData.map(cacheKey => new Promise((resolve, reject) => {
	const dbKey = `workbox-cache-expiration-${scope}-${cacheKey}`;
	const request = indexedDB.deleteDatabase(dbKey);
	request.onerror = reject;
	request.onsuccess = resolve
})));

await idbDeletePromises;

@josephliccini
Copy link
Contributor

josephliccini commented May 17, 2018

Does workbox close connections to indexedDB?

I am having issues where my deleteDatabase request is continually hitting the onblocked callback.

The suggestions online recommend closing all open IndexedDB requests before calling deleteDatabase. Is there a way we could do this in Workbox?

Thanks!

@josephliccini
Copy link
Contributor

I was able to (hackily) close all connections via monkey-patching the indexedDB.open method to keep track of open requests.

Then before deleting indexedDBs, I close all open connections, then do deleteDatabase.

Code is like this:

// Taken from : https://gist.github.com/cdegit/22a2aa0cba36171d0c6a023a40127f1c
const overrideFunction = function(object: any, key: any, override: any) {
    let originalFn: any;
    const applyOverride = function() {
        // Use call to make sure the this is correct
        return override.call(this, originalFn, arguments);
    };

    // If the function already exists,
    // grab a reference to it before we override its getter
    if (typeof object[key] === 'function') {
        originalFn = object[key];
    }

    try {
        Object.defineProperty(object, key, {
            get: function() {
                if (originalFn) {
                    // Capture the arguments and pass them to the override
                    return applyOverride;
                }
            },
            set: function(fn) {
                originalFn = fn;
            }
        });
    } catch (e) {
        console.log('Unable to override function');
        console.log(e);
    }
};

const connections: Array<IDBOpenDBRequest> = [];
overrideFunction(indexedDB, 'open', function(originalFn: any, originalArguments: any) {
    const result = originalFn.apply(this, originalArguments);

    connections.push(result);
    console.log(connections);

    return result;
});

// .. later

function onLogout() {
    connections.forEach(connection => connection.result.close());
    connections.length = 0;
    clearCachesAndIndexedDBs();
}

@jeffposnick
Copy link
Contributor Author

No, Workbox deliberately keeps connections to IDB open while the SW remains running, which unfortunately necessitates the types of hacks that you put together.

The "official" method for cleaning up the IDB + cache storage pair will have to take that into account.

@josephliccini
Copy link
Contributor

Thanks Jeff, looking forward to an official implementation 👍

@josephliccini
Copy link
Contributor

Awesome! looking forward to hooking this up!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants