Astro cache miss and bypass

Hi all.

I’ve used this guide to try and put together a quick proof-of-concept for a stale-while-revalidate cache strategy, leveraging Netlify’s great ISR/cache model.

I have a demo site here (SSR with the Netlify adapter): https://astro-relume-netlify.in-beta.link/.

In the front-matter of the index route, I have:

Astro.response.headers.set(
  "Cache-Control",
  "public, max-age=0, must-revalidate"
);

Astro.response.headers.set(
  "Netlify-CDN-Cache-Control",
  "public, durable, s-maxage=300, stale-while-revalidate=604800"
);

What I expect to happen is that the first visitor after a deploy would get a miss and then subsequent visit with the would receive a hit or a stale copy.

What I see is that every new visitor gets an edge miss and a durable bypass, with the response headers looking like this:

cache-control: public,max-age=0,must-revalidate
cache-status: "Netlify Durable"; fwd=bypass
cache-status: "Netlify Edge"; fwd=miss

The page doesn’t use any cookies or query strings etc. and to rule anything specific to that page out, I’ve added a test route of Cache Test which only contains the following in a single index.astro file:

---
Astro.response.headers.set(
  "Cache-Control",
  "public, max-age=0, must-revalidate"
);
Astro.response.headers.set(
  "Netlify-CDN-Cache-Control",
  "public, durable, s-maxage=300, stale-while-revalidate=604800"
);
---

<html>
  <head><title>Cache Test</title></head>
  <body>
    <h1>Cache Test Page</h1>
    <p>Testing Netlify caching: {new Date().toISOString()}</p>
  </body>
</html>

But the response headers come back the same and you can see a fresh time stamp with each refresh.

Any ideas what I’m doing wrong here?

Some kind of progress, although this has also confused me slightly more…

I’ve made a second test page, with everything else stripped out with these headers:

Astro.response.headers.set(
  "Cache-Control",
  "public, max-age=0, must-revalidate"
);

Astro.response.headers.set(
  "CDN-Cache-Control",
  "public, durable, s-maxage=60, stale-while-revalidate=604800"
);

The main change here is changing "Netlify-CDN-Cache-Control" to "CDN-Cache-Control". If I keep the Netlify prefix then no caching seems to happen at all.

Now the caching seems to kind of work. What I mean by that is I can see the time output remain the same for the 60 seconds, then update, which is what I would expect with the headers. However, it doesn’t look like the “durable” aspect is working. If you refresh the page a bunch of time, you mostly see:

cache-control: public,max-age=0,must-revalidate
cache-status: "Netlify Edge"; hit
cdn-cache-control: public, durable, s-maxage=300, stale-while-revalidate=604800

However, every now and again but before the s-maxage has expired, you get a much longer response time and the following response headers:

cache-control: public,max-age=0,must-revalidate
cache-status: "Netlify Durable"; hit; ttl=20
cache-status: "Netlify Edge"; fwd=miss
cdn-cache-control: public, durable, s-maxage=60, stale-while-revalidate=604800

This time there seems to be a durable hit and an edge miss. But then refresh the page again and you go back to an edge hit and no mention of durable. The difference in response time is many fold; the edge hits have a response time of ~20ms while the durable hits have a response time of ~450ms.

Finally, I would also expect the stale cache to be served while a fresh copy was generated. However, once the s-maxage passes and I see a stale cache like this:

age: 814
cache-control: public,max-age=0,must-revalidate
cache-status: "Netlify Edge"; hit; fwd=stale
cdn-cache-control: public, durable, s-maxage=60, stale-while-revalidate=604800

The response time is high, around ~400ms. I’d expect to see times that are the same as a cache hit.

On that route, we’re skipping durable cache because of invalid vary. netlify-vary is set to none for some reason, which is invalid. Not sure where it’s coming from, but that’s the reason for the issue.

What’s the URL for the second page?

Hi @hrishikesh. Thanks for the reply.

I was trying to rule out any possibility of the page skipping the cache with netlify-vary set to none. I’ve now removed this.

On the index route, I’ve removed the netlify-vary header. I do now see cache hits, although it’s very strange as I only added that header after I was getting only cache misses before but now it seems to work by removing it and having not changed anything else.

What I’m typically seeing now:

cache-status: "Netlify Edge"; hit

With a very low response time of ~20ms.

But when the revalidation time passes (it’s set to 60s for now), the response headers are:

cache-status: "Netlify Durable"; hit; ttl=200
cache-status: "Netlify Edge"; fwd=miss

With a higher response time ~450ms.

Apologies for missing the second link, it is: here but now the behaviour is similar between the home page / index and the this new link.

Is what’s happening here that the majority of the time I’m getting an edge cache that already exists on a node close to me because my previous visits triggered them but when the s-maxage time passes , I get the stale copy instead from the durable cache, which appears to have much higher response times?

I can confirm I’m seeing the behaviour similar to your report. I’ve asked the devs, if these timings or expected or not.

1 Like

Any update @hrishikesh?