Getting Google Cloud CDN to serve stale file on 404

1.5k views Asked by At

My frontend runs on nginx, and I'm serving a bunch of .chunk.js files that are built from react.

Every time I update my frontend, I rebuild the docker image and update the kubernetes deployment. However, some users might still be trying to fetch the old js files.

I would like Google Cloud CDN to serve the stale, cached version of the old files, however it seems that it will only serve stale content in the event of errors or the server being unreachable, not a 404.

Cloud CDN also has something called "negative caching", however that seems to be for deciding how long a 404 is cached.

--> What's the best way to temporarily serve old files on Google Cloud? Can this be done with Cloud CDN?

(Ideally without some funky build process that requires deploying the old files as well)

4

There are 4 answers

5
Kevin Danikowski On BEST ANSWER

I have this issue as well, if you find a way to set it up on Google CDN please let me know.

Here is my Workaround:

  1. Choose Use origin settings based on Cache-Control headers

  2. Since most browsers cache static JS assets, I reduce my Cache-Control header for .html to be reasonably low or normal, like 5-60 minutes, whereas the javascript files have a much longer cache time, like a week.

Some Context: After deployment, if google serves the old index.html from its CDN cache, the user's browser will request old JS files. If it's time for those JS files to be re-validated, google will see they are now 404s, and send a 404 response instead of the JS file. The workaround above makes sure that the JS files a highly likely to be available in the cache, while the index.html is updated more frequently.

Update: This works... but there appears to be a caveat, if the page isn't a frequently trafficked page, google will eventually return a 404 on the javascript file before the specified time. Even though google docs state it won't get revalidated for 30 days, this appears to be false.

Update 2: Google's Response:

The expiration doc says "Cloud CDN revalidates cached objects that are older than 30 days." It doesn't say that Google won't revalidate prior to 30 days. Things fall out of cache arbitrarily quickly and max-age is just an upper bound.

3
Nexus Software Systems On

The serveWhileStale setting combines both the stale-while-revalidate and the stale-if-error HTTP caching features.

The default, minimum, and maximum values are as follows:

Default: 86,400 seconds (one day)
Minimum: 0 seconds (disables the feature)
Maximum: 604,800 seconds (one week)

Stale content is served up to the specified limit past the cache entry expiration time, which is defined by the max-age, s-max-age, or Expires headers.

See more at : https://cloud.google.com/cdn/docs/serving-stale-content

0
DemiPixel On

It's unclear if the original problem is possible to solve, but given this is a popular question, I figured I'd share my workaround for static assets (JS, CSS, images, etc, that don't have any special permissions):

I have my CI/CD use a bucket (or "Space" in Digital Ocean) and upload all the JS/CSS/etc files there:

s3cmd sync -P --no-mime-magic --guess-mime-type ./build/assets/ s3://my-bucket-name/frontend/assets/

I then have a script to delete files older than 30 days:

s3cmd ls s3://my-bucket-name/frontend/assets | while read -r line;
  do
    createDate=`echo $line|awk {'print $1" "$2'}`
    createDate=`date -d"$createDate" +%s`
    olderThan=`date -d"-30d" +%s`
    if [[ $createDate -lt $olderThan ]]
      then 
        fileName=`echo $line|awk {'print $4'}`
        echo "Deleting stale $fileName"
        if [[ $fileName != "" ]]
          then
            s3cmd del "$fileName"
        fi
    fi
  done;

Finally, you'll want to setup cdn.your-site.com to point to the bucket/CDN, and update your build process so that assets are accessed using cdn.your-site.com (in Vite, I use a custom renderBuiltUrl that checks for NODE_ENV === 'production' and type === 'asset').

This whole process means that old assets will stay up for 30 days, allowing old sessions to access them. The bucket pricing is extremely minimal and the CDN costs are identical.

0
Inshaal93 On

You can set Cache-Control: max-stale=<seconds> as a response header in your application. This will allow stale content for a set number of seconds. It's handy if this is happening after new deployments. But still set your html files to either not cache or a short TTL as Kevin said.

Source