<html><head><meta http-equiv="Content-Type" content="text/html; charset=us-ascii"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><div class="">Hi Luca,</div><div class=""><br class=""></div><div class="">As Dridi and Guillaume said, what you're looking for is something like the stale VMOD. I think the OSS approach suggested by Guillaume could be extended a little bit in order to improve performance and avoid request serialization. Problem is the final VCL is *ugly* and hard to understand. In any case, next I'm sharing a VTC showing how it works:</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class="">varnishtest "Full vs. limited grace"</div><div class=""><br class=""></div><div class="">server s_backend {</div><div class=""> # First request when the cache is empty (see 1).</div><div class=""> rxreq</div><div class=""> txresp</div><div class=""><br class=""></div><div class=""> # Background fetch done while inside the limited grace period (see 2).</div><div class=""> rxreq</div><div class=""> txresp</div><div class=""><br class=""></div><div class=""> # Another request to refresh the content after the limited grace period has</div><div class=""> # finished (see 3).</div><div class=""> rxreq</div><div class=""> txresp</div><div class=""><br class=""></div><div class=""> # Another request to refresh the content after the limited grace period has</div><div class=""> # finished one more time (see 4). This time, we return an error so a cached</div><div class=""> # version will have to be returned to the client.</div><div class=""> rxreq</div><div class=""> txresp -status 500</div><div class="">} -start</div><div class=""><br class=""></div><div class="">varnish v_backend -vcl {</div><div class=""> import std;</div><div class=""><br class=""></div><div class=""> backend default {</div><div class=""> .host = "${s_backend_addr}";</div><div class=""> .port = "${s_backend_port}";</div><div class=""> }</div><div class=""><br class=""></div><div class=""> sub vcl_recv {</div><div class=""> # Clean up internal headers.</div><div class=""> if (req.restarts == 0) {</div><div class=""> unset req.http.X-Varnish-Restarted-5xx;</div><div class=""> }</div><div class=""> unset req.http.X-Varnish-Use-Limited-Grace;</div><div class=""><br class=""></div><div class=""> # Set a limited grace unless a restart has been done to use full grace.</div><div class=""> if (!(req.restarts > 0 && req.http.X-Varnish-Restarted-5xx)) {</div><div class=""> set req.http.X-Varnish-Use-Limited-Grace = "1";</div><div class=""> set req.grace = 2s;</div><div class=""> } else {</div><div class=""> set req.grace = 100y;</div><div class=""> }</div><div class=""> }</div><div class=""><br class=""></div><div class=""> sub vcl_backend_response {</div><div class=""> set beresp.ttl = 1s;</div><div class=""><br class=""></div><div class=""> # Set full grace value. This could be done by returning a proper value for</div><div class=""> # the stale-while-revalidate property in the Cache-Control header, which</div><div class=""> # Varnish understands (that's not the case with the stale-if-error</div><div class=""> # property).</div><div class=""> set beresp.grace = 24h;</div><div class=""><br class=""></div><div class=""> # Send requests with a broken backend response to vcl_backend_error so they</div><div class=""> # can be restarted.</div><div class=""> if (beresp.status >= 500 && beresp.status < 600) {</div><div class=""> return (error);</div><div class=""> }</div><div class=""> }</div><div class=""><br class=""></div><div class=""> sub vcl_backend_error {</div><div class=""> if (bereq.http.X-Varnish-Use-Limited-Grace && !bereq.uncacheable) {</div><div class=""> # Trigger restart in the client side in order to enable full grace and</div><div class=""> # try to deliver a staled object. Also, cache error response but under</div><div class=""> # a variant to avoid overwritting the staled object that may already be</div><div class=""> # in cache. Grace and keep are explicitly disabled to overwrite current</div><div class=""> # default behaviour (<a href="https://github.com/varnishcache/varnish-cache/issues/3024" class="">https://github.com/varnishcache/varnish-cache/issues/3024</a>).</div><div class=""> set beresp.http.X-Varnish-Restart-5xx = "1";</div><div class=""> set beresp.ttl = 1s;</div><div class=""> set beresp.grace = 0s;</div><div class=""> set beresp.keep = 0s;</div><div class=""> set beresp.http.Vary = "X-Varnish-Use-Limited-Grace";</div><div class=""> return (deliver);</div><div class=""> } else {</div><div class=""> # Jump to 'vcl_synth' with a 503 status code.</div><div class=""> return (abandon);</div><div class=""> }</div><div class=""> }</div><div class=""><br class=""></div><div class=""> sub vcl_deliver {</div><div class=""> # Execute restart if the backend side requested so (see 'vcl_backend_error').</div><div class=""> if (resp.http.X-Varnish-Restart-5xx && !req.http.X-Varnish-Restarted-5xx) {</div><div class=""> set req.http.X-Varnish-Restarted-5xx = "1";</div><div class=""> return (restart);</div><div class=""> }</div><div class=""><br class=""></div><div class=""> # Clean up Vary header.</div><div class=""> if (resp.http.Vary == "X-Varnish-Use-Limited-Grace") {</div><div class=""> unset resp.http.Vary;</div><div class=""> }</div><div class=""><br class=""></div><div class=""> # Debug.</div><div class=""> set resp.http.X-Cache-Hits = obj.hits;</div><div class=""> }</div><div class=""><br class=""></div><div class=""> sub vcl_backend_fetch {</div><div class=""> # Clean up internal headers.</div><div class=""> if (bereq.retries == 0) {</div><div class=""> unset bereq.http.X-Varnish-Restart-5xx;</div><div class=""> }</div><div class=""><br class=""></div><div class=""> # Do not retry requests restarted due to 5xx backend responses, no</div><div class=""> # matter if a staled object has not been found or if a bgfetch has been</div><div class=""> # spawned after serving staled content.</div><div class=""> if (bereq.retries == 0 && bereq.http.X-Varnish-Restarted-5xx) {</div><div class=""> # Jump to 'vcl_synth' with a 503 status code.</div><div class=""> return (abandon);</div><div class=""> }</div><div class=""> }</div><div class="">} -start</div><div class=""><br class=""></div><div class="">client c1 -connect ${v_backend_sock} {</div><div class=""> # 1: Ask for a content. This will hit the backend as the cache is empty.</div><div class=""> txreq</div><div class=""> rxresp</div><div class=""> expect resp.status == 200</div><div class=""> expect resp.http.X-Cache-Hits == 0</div><div class=""><br class=""></div><div class=""> # Wait until the TTL is over.</div><div class=""> delay 1.5</div><div class=""><br class=""></div><div class=""> # 2: Further requests to the same content inside the limited grace period</div><div class=""> # (set to 2 seconds) will be resolved by the cache. A bgfetch to the</div><div class=""> # backend is silently made.</div><div class=""> txreq</div><div class=""> rxresp</div><div class=""> expect resp.status == 200</div><div class=""> expect resp.http.X-Cache-Hits == 1</div><div class=""><br class=""></div><div class=""> # Wait until the new TTL and new limited grace period are over.</div><div class=""> delay 5.0</div><div class=""><br class=""></div><div class=""> # 3: Even if the content is in the cache (it's being stored for the full</div><div class=""> # cache period: 24 hours), limited grace makes sure fresh content is</div><div class=""> # recovered from the backend. A request to the content, therefore,</div><div class=""> # produces a new hit in the backend.</div><div class=""> txreq</div><div class=""> rxresp</div><div class=""> expect resp.status == 200</div><div class=""> expect resp.http.X-Cache-Hits == 0</div><div class=""><br class=""></div><div class=""> # Wait again until the new TTL and new limited grace period are over.</div><div class=""> delay 3.5</div><div class=""><br class=""></div><div class=""> # 4: A new request will try to get fresh content, but the backend now returns</div><div class=""> # an error response, so Varnish restarts the request and serves stalled</div><div class=""> # content. No background fetch is done as Varnish abort the attempt to</div><div class=""> # disturb the failing backend.</div><div class=""> txreq</div><div class=""> rxresp</div><div class=""> expect resp.status == 200</div><div class=""> expect resp.http.X-Cache-Hits == 1</div><div class="">} -run</div><div class=""><br class=""></div><div class="">varnish v_backend -expect client_req == 4</div></blockquote><div class=""><br class=""></div><div class="">Best,</div><div class=""><br class=""></div><div class="">--</div><div class="">Carlos Abalde</div><div class=""><br class=""></div></body></html>