Consider adding `maxUnusedSeconds` and `updateStale` to `ExpirationPlugin` config
See original GitHub issueLibrary Affected: workbox-expiration
Issue or Feature Request Description: Hi there! Thanks for making this incredibly useful tool 😃
I have a bunch of use cases where I need to either update a resource periodically or where I need to remove a resource that hasn’t been used for a while. The ExpirationPlugin
with maxAgeSeconds
can sort of solve these use cases, but it isn’t elegant and it has many bad edge cases.
I have tried to fix my use cases by making some custom plugins, but it is very complicated and requires a lot of IndexedDB calls. I then realised that 95% of the code I need has already been written for the maxAgeSeconds
parameter, so maybe I should just propose some minor updates to workbox instead. And now that I have thought it through, I actually think this could solve a long list of challenges that would otherwise require custom code.
I will start with my proposed additions, then show an example. I am happy to discuss this in more detail, or provide more detailed use cases if you’d like 😃
Proposed additions
The ExpirationPlugin
gets two new parameters in its config:
maxUnusedSeconds
number
This will be almost identical to maxAgeSeconds
, but instead of calculating the time since the resource was last fetched, it calculates the time since the resource was last used on the website. In other words, how long ago was a request
made for the cached resource.
As with maxAgeSeconds
, if the resource hasn’t been used for that amount of time, it is removed from the cache.
updateStale
boolean
When a cached resource is older than maxAgeSeconds
, it will normally be removed from the cache, but if updateStale
is set to true, the plugin will instead try to refetch and update the cached resource. If the update fails, the old resource is kept.
This parameter does not affect removals caused by maxEntries
or maxUnusedSeconds
.
Example: A better image caching recipe
The default image caching recipe shows a simple “cache this for 30 days, then delete” use case.
Let’s consider that plugin setup:
new ExpirationPlugin({
maxEntries: 60,
maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
}),
…vs a default plugin setup that leverages the proposed options:
new ExpirationPlugin({
maxEntries: 60,
maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
updateStale: true,
maxUnusedSeconds: 30 * 24 * 60 * 60, // 30 Days
})
Imagine that a user has been looking at an image every day for some time, but loses their internet connection 28 days after they saw the image for the first time, and the connection ends up being down for 7 days.
With the current setup, the image disappears 2 days after the internet goes down, and is missing for 5 days until the internet comes back up. There was no reason to delete the image, so this is not ideal. With the proposed setup, there will be a failed attempt at updating the image after 2 days, but since it was very recently seen, it will be kept for 5 days until it can eventually be updated.
Now imagine that the image is completely static and never requires updates, and that the user has this app for 5 years.
With the current setup, the app must delete the image once every 30 days, so it will have to download identical copies of the image 120 times. It isn’t possible to fix this, because we want the image to expire if it isn’t used.
With the proposed setup, this would not be nearly as big a problem, because the image can be ETag
validated, meaning it won’t be downloaded again if the server copy hasn’t changed.
With the proposed setup, it would also be possible to change the setup slightly so that no network activity occurs at all for all 5 years:
new ExpirationPlugin({
maxEntries: 60,
maxUnusedSeconds: 30 * 24 * 60 * 60, // 30 Days
})
Issue Analytics
- State:
- Created 2 years ago
- Reactions:1
- Comments:12 (3 by maintainers)
Top GitHub Comments
I would actually take a guess that most people are looking for
maxUnusedSeconds
(not the currentmaxAgeSeconds
). My use-case is perfectly illustrated by the original issue body. I have an image in my app that represents a profile picture and I only want to remove it from cache if it has not been accessed for the specified time.A change of profile picture changes the URL, so I want to remove outdated URLs based off of when they were last accessed (because the caches never get out of date and it is not uncommon for someone to rarely update their profile picture). If someone changes profile picture, I want to eventually remove that from cache.
Instead of adding an extra
maxUnusedSeconds
anupdateOnAccess
or similar could be added, which means thatupdateTimestamp()
would now be called on cache access as well (assuming usage ofCacheFirst
of course).@jeffposnick I noticed you added this to the v7 milestone, which sounds great! I just wanted to remind you that I am happy to submit a PR for these changes, although I can’t give any guarantees as to when the PR would be ready 😃