Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change backend during retry in Varnish 4

I'd like to be able to change the backend on a retry in Varnish 4. We've got this working on a different (older) application using Varnish 3, but I haven't been able to figure it out for v4, nor find much documentation. The setup we want is to have 2 sets of directors - one for the initial request trying a local server in the same datacenter as varnish because this is way faster, and then only if that fails, pick randomly from a different director for servers in other datacenters.

In v3, this was easy:

sub vcl_recv {
    if (req.restarts == 0) {
        set req.backend = defaultdirector;
    } else {
        set req.backend = backupdirector;
    }
}

#Then in vcl_fetch and/or vcl_error something like:
if (beresp.status >= 500 && req.restarts < some_max) {
    return(restart);
}

But now in v4, restart has supposedly been replaced with retry, with the entire documentation being:

In 3.0 it was possible to do return(restart) after noticing that the backend response was wrong, to change to a different backend.

This is now called return(retry), and jumps back up to vcl_backend_fetch.

This only influences the backend fetch thread, client-side handling is not affected.

Yet I still see a few people's example code containing return(restart) rather than return(retry), and not a single example of it working with the retry command.

I understand that varnish should not have to do all of the work in vcl_recv again (such as stripping cookies), since it was only the communication with the backend that failed, so it does make sense to bounce back to the backend fetch rather than redo all the frontend processing, but I get a compile error if I try to change the backend in vcl_backend_fetch. How do I make this work?

like image 455
Inukshuk Avatar asked Feb 18 '16 00:02

Inukshuk


1 Answers

the official documentation is kind of misleading. In fact, restart still exists: you can catch the error in vcl_deliver and set the backend accordingly in vcl_recv using req.backend_hint:

sub vcl_recv {
    if (req.restarts == 0) {
        set req.backend_hint = defaultdirector.backend();
    } else {
        set req.backend_hint = backupdirector.backend();
    }
}

sub vcl_deliver {
    if (resp.status >= 500 && req.restarts < some_max) {
        return(restart);
    }
}

Or, if it is more adequate, you can use retry between vcl_backend_response and vcl_backend_fetch:

sub vcl_backend_fetch {
    if (bereq.retries > 0) {
        set bereq.backend = backupdirector.backend();
    }
}

sub vcl_backend_response {
    if (beresp.status >= 500 && bereq.retries < some_max) {
        return(retry);
    }
}
like image 91
komuta Avatar answered Oct 19 '22 16:10

komuta