Varnish 6.x — stale-if-error implementation

The only real solution to implement both stale-if-error and stale-while-revalidate is by using vmod_stale in Varnish Enterprise.

Here's a stale-while-revalidate implementation in regular VCL, but it doesn't have the flexibility to set stale-while-revalidate via the Cache-Control header:

vcl 4.1;

import std;

backend default {
    .host="localhost";
    .port="8080";
    .probe={
        .url="/";
    }
}

sub vcl_recv {
    if (std.healthy(req.backend_hint)) {
        set req.grace = 10s;
    }
}

sub vcl_backend_response {
    set beresp.http.sie = std.integer(regsub(beresp.http.Cache-Control,"^.*stale-if-error=([0-9]+).*$","\1"),0);        
    set beresp.grace = std.duration(beresp.http.sie + "s",beresp.grace);
}

This example sets grace to whatever the value of Cache-Control: stale-if-error=... is. In vcl_recv we can limit this value if the server is healthy, but the grace value is hardcoded and cannot come from Cache-Control: stale-while-revalidate=....

beresp.keep won't work in this case, because it is only used to keep the object around for synchronous revalidation, whereas grace can be used to serve stale data.

The reason why we developed vmod_stale is to re-arm objects and set new TTL, grace & keep values. By initially setting the keep value to an very high number, we ensure that the object is kept around, and vmod_stale can then re-arm it.

Your options are to either use my poor man's stale-if-error implementation, or upgrade to Varnish Enterprise.

Sidenote about Varnish Enterprise

One easy way to try out Varnish Enterprise without upfront licensing payments, if you’re interested, is to spin up an instance on cloud infrastructure:

  • Varnish Enterprise on AWS
  • Varnish Enterprise on Azure
  • Varnish Enterprise on GCP