workbox: fetchDidFail with StaleWhileRevalidate is not called
Library Affected: workbox v5.1.3 npm
Browser & Platform: Google Chrome v85
Issue or Feature Request Description:
I don’t seem to get how to run some code when a fetch in a StaleWhileRevalidate
strategy fails. I’d like to use the callback to detect offline usage, but fetchDidFail
is not called when I tick “offline” and reload the pahe. (fetchDidSucceed
works tho). Is this expected? I didn’t find any mention of that in the documentation.
Here’s an example:
const messageIfFail: WorkboxPlugin = {
fetchDidFail: async function () {
// No return expected.
// NOTE: `originalRequest` is the browser's request, `request` is the
// request after being passed through plugins with
// `requestWillFetch` callbacks, and `error` is the exception that caused
// the underlying `fetch()` to fail.
while (true) {
console.log("called");
}
// send message to client
}
}
registerRoute(
({url}) => {
return url.origin == "https://fonts.googleapis.com"
|| url.origin == "https://cdn.jsdelivr.net"
},
new StaleWhileRevalidate({
cacheName: 'cdn',
plugins: [
messageIfFail
]
})
);
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Comments: 16 (2 by maintainers)
When attempting to debug this, I would suggest starting fresh from an Incognito window, and additionally, not checking Disable Cache. It sounds like you’ve made a number of changes to your SW during development, and it would be good to rule out inconsistent cache state (using the Incognito window) while also replicating what users will actually see in production (don’t check Disable Cache).
You might see a log message about a failed
fetch()
made byStaleWhileRevalidate
in development, but if the strategy uses a cached response from the Cache Storage API to satisfy the request, the “catch” handler won’t run. The “catch” handler only runs when there’s no response (fromfetch()
or Cache Storage API) that can be used by a strategy.FWIW, your code could be simplified to:
@TheForsakenSpirit So sorry! Changed the code without re-checking.
@jeffposnick Very well, I’ve seen some responses have 80000+ seconds on max-age, but that’s ok, I don’t actually need to detect the connection status, just signal the app went to “offline mode”. Until an http cached response expires, I can consider it indistinguishable from online work. Hoping that I’m not forgetting something stupid again, I still have two errors I can’t manage to solve.
Only this route is affected. (I also have the recommended route for Google Fonts font files, but it has never given errors as now. I clear the application data regularly during testing)
This happens randomly, when opening the browser. If it occurs, it doesn’t go away until the app data is cleared. I have no Idea why. Normally cross-origin requests are correctly stored as “cors”. (Only if made explicit through html). This one breaks the sw functionality.
This happens instead when the app is offline and the http cache is disabled (“Disable Cache” ticked). This is the “development” version, the same errors appears in “production” mode too. The same errors show up in a completely generated sw. Since service workers exist to provide offline support, I’m surely missing something here.
This is the code I’m using:
fetchDidFail
will execute when the underlyingfetch()
fails when usingStaleWhileRevalidate
, even if the strategy ends up using a response from the Cache Storage API.I see from your sample route that you’re attempting to use this with subresources loaded from a CDN, and in most cases, responses to those sorts of URLs will use long-lived
Cache-Control
headers that don’t require revalidation. So what my guess is as to what’s happening is that even when you’re offline, the underlyingfetch()
request succeeds, rather than fails, since a cache hit in the browser’s “normal” HTTP cache is sufficient, andfetch()
never ends up going against the network anyway.You can see this in action at https://glitch.com/edit/#!/upbeat-rebel-octopus?path=sw.js, where the example is for a HTTP response that has a maximum age of 20 seconds. If you go offline and try again within 20 seconds of populating the “normal” HTTP cache with a response, then the
fetch()
will be fulfilled from the HTTP cache. If you wait longer than 20 seconds, then the response in the HTTP cache will be considered too old to use without revalidation, and thefetch()
will fail when it makes the network request to revalidate.I’m going to close this for now, but if I’m misinterpreting anything, let me know and we can revisit.
@Lucide
requestWillFetch
must returnRequest
object. Check this.Alright. I find that to be a bit misleading tho. Because it mentions “fetch” specifically, “request” might be better? Maybe some more explanatory lines in the docs. Thank you!