question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Consider adding `maxUnusedSeconds` and `updateStale` to `ExpirationPlugin` config

See original GitHub issue

Library 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:open
  • Created 2 years ago
  • Reactions:1
  • Comments:12 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
Bluenix2commented, Sep 8, 2022

I would actually take a guess that most people are looking for maxUnusedSeconds (not the current maxAgeSeconds). 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 an updateOnAccess or similar could be added, which means that updateTimestamp() would now be called on cache access as well (assuming usage of CacheFirst of course).

1reaction
atjncommented, Jan 2, 2022

@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 😃

Read more comments on GitHub >

github_iconTop Results From Across the Web

workbox-expiration - Chrome Developers
Workbox provides this functionality through the workbox-expiration plugin that allows you to limit the number of entries in a cache and / or ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found