Search code examples
varnishvarnish-vcl

Change cache control directive for stale responses in Varnish


This is my first time experimenting with Varnish.

We noticed our CDN not doing any request coalescing, so as an experiment I'm allowed to try out Varnish.

However I can't seem to figure out how to modify the response headers when stale content is served.

Image the following vcl and all backend responses have max-age=60, public, s-maxage=600 as the cache-control directive.

sub vcl_backend_response {
    set beresp.grace = 3600s;
    return (deliver);
}

When I:

  • visit /foo
  • do a varnish soft purge and a subsequent CDN (hard) purge on /foo
  • visit /foo again

When visiting /foo for the second time I'll immediately get a (stale) response. However I don't want it to have the same cache-control directive anymore, because then my CDN will continue to serve this stale response for another 10 minutes.

Is it possible to change the cache-control directive for stale content to max-age=0, public, s-maxage=10?


Solution

  • Here's the VCL code you need to modify the Cache-Control header for stale content:

    vcl 4.1;
    
    sub vcl_deliver {
        //set resp.http.x-ttl = obj.ttl;
        //set resp.http.x-grace = obj.grace;
        if(obj.ttl <= 0s && obj.grace > 0s ) {
            set resp.http.Cache-Control = "max-age=0, public, s-maxage=10";
        } 
    }
    

    If you want to debug the process, just uncomment the 2 lines and look for the x-ttl and x-grace response headers to see the remaining values for both timers.

    Although you can control the staleness by setting beresp.grace in VCL, you can also set the staleness through the stale-while-revalidate directive in the Cache-Control header.

    Here's an example:

    Cache-Control: max-age=60, public, s-maxage=600, stale-while-revalidate=3600
    

    This will allow the browser to cache for a minute, allow intermediary servers to cache for 10 minutes and set an allowed staleness of an hour while revalidating outdated content.