By Tollef's request, here's the fallback director patch that applies cleanly to current trunk. I managed to get something else into the previous patch I linked from github.

Cheers,

        Rogier/DocWilco
diff --git a/bin/varnishd/cache_backend.h b/bin/varnishd/cache_backend.h
index d2de06e..21a7061 100644
--- a/bin/varnishd/cache_backend.h
+++ b/bin/varnishd/cache_backend.h
@@ -156,4 +156,5 @@ dir_init_f VRT_init_dir_dns;
 dir_init_f VRT_init_dir_hash;
 dir_init_f VRT_init_dir_random;
 dir_init_f VRT_init_dir_round_robin;
+dir_init_f VRT_init_dir_fallback;
 dir_init_f VRT_init_dir_client;
diff --git a/bin/varnishd/cache_backend_cfg.c b/bin/varnishd/cache_backend_cfg.c
index e6c935c..0582f72 100644
--- a/bin/varnishd/cache_backend_cfg.c
+++ b/bin/varnishd/cache_backend_cfg.c
@@ -256,6 +256,8 @@ VRT_init_dir(struct cli *cli, struct director **dir, const 
char *name,
                VRT_init_dir_dns(cli, dir, idx, priv);
        else if (!strcmp(name, "round-robin"))
                VRT_init_dir_round_robin(cli, dir, idx, priv);
+       else if (!strcmp(name, "fallback"))
+               VRT_init_dir_fallback(cli, dir, idx, priv);
        else if (!strcmp(name, "client"))
                VRT_init_dir_client(cli, dir, idx, priv);
        else
diff --git a/bin/varnishd/cache_dir_round_robin.c 
b/bin/varnishd/cache_dir_round_robin.c
index 2a6009a..61d80fc 100644
--- a/bin/varnishd/cache_dir_round_robin.c
+++ b/bin/varnishd/cache_dir_round_robin.c
@@ -47,10 +47,13 @@ struct vdi_round_robin_host {
        struct director                 *backend;
 };
 
+enum mode_e { m_round_robin, m_fallback };
+
 struct vdi_round_robin {
        unsigned                        magic;
 #define VDI_ROUND_ROBIN_MAGIC          0x2114a178
        struct director                 dir;
+       enum mode_e                     mode;
        struct vdi_round_robin_host     *hosts;
        unsigned                        nhosts;
        unsigned                        next_host;
@@ -68,9 +71,17 @@ vdi_round_robin_getfd(const struct director *d, struct sess 
*sp)
        CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
        CAST_OBJ_NOTNULL(vs, d->priv, VDI_ROUND_ROBIN_MAGIC);
 
+       /* 
+        * In fallback mode we ignore the next_host and always grab the 
+        * first healthy backend we can find.
+        */
        for (i = 0; i < vs->nhosts; i++) {
-               backend = vs->hosts[vs->next_host].backend;
-               vs->next_host = (vs->next_host + 1) % vs->nhosts;
+               if (vs->mode == m_round_robin) {
+                       backend = vs->hosts[vs->next_host].backend;
+                       vs->next_host = (vs->next_host + 1) % vs->nhosts;
+               } else /* m_fallback */ {
+                       backend = vs->hosts[i].backend;
+               }
                if (!VDI_Healthy(backend, sp))
                        continue;
                vbe = VDI_GetFd(backend, sp);
@@ -114,9 +125,9 @@ vdi_round_robin_fini(const struct director *d)
        FREE_OBJ(vs);
 }
 
-void
-VRT_init_dir_round_robin(struct cli *cli, struct director **bp, int idx,
-    const void *priv)
+static void
+vrt_init_dir(struct cli *cli, struct director **bp, int idx,
+    const void *priv, enum mode_e mode)
 {
        const struct vrt_dir_round_robin *t;
        struct vdi_round_robin *vs;
@@ -141,6 +152,7 @@ VRT_init_dir_round_robin(struct cli *cli, struct director 
**bp, int idx,
        vs->dir.fini = vdi_round_robin_fini;
        vs->dir.healthy = vdi_round_robin_healthy;
 
+       vs->mode = mode;
        vh = vs->hosts;
        te = t->members;
        for (i = 0; i < t->nmember; i++, vh++, te++) {
@@ -152,3 +164,18 @@ VRT_init_dir_round_robin(struct cli *cli, struct director 
**bp, int idx,
 
        bp[idx] = &vs->dir;
 }
+
+void
+VRT_init_dir_round_robin(struct cli *cli, struct director **bp, int idx,
+    const void *priv)
+{
+       vrt_init_dir(cli, bp, idx, priv, m_round_robin);
+}
+
+void
+VRT_init_dir_fallback(struct cli *cli, struct director **bp, int idx,
+    const void *priv)
+{
+       vrt_init_dir(cli, bp, idx, priv, m_fallback);
+}
+
diff --git a/bin/varnishtest/tests/v00036.vtc b/bin/varnishtest/tests/v00036.vtc
new file mode 100644
index 0000000..c039650
--- /dev/null
+++ b/bin/varnishtest/tests/v00036.vtc
@@ -0,0 +1,132 @@
+varnishtest "Test fallback director"
+
+server s1 {
+       rxreq
+       expect req.url == "/"
+       txresp -body "slash"
+} -start
+
+server s2 {
+       rxreq
+       expect req.url == "/"
+       txresp -body "slash"
+} -start
+
+server s3 {
+       rxreq
+       expect req.url == "/foo"
+       txresp -hdr "Foo: 3" -body "foobar"
+} -start
+
+varnish v1 -vcl {
+
+       probe p1 {
+               .url = "/";
+               .timeout = 1s;
+               .interval = 1s;
+               .window = 4;
+               .threshold = 3;
+               .initial = 0;
+       }
+       probe p2 {
+               .url = "/";
+               .timeout = 1s;
+               .interval = 1s;
+               .window = 3;
+               .threshold = 2;
+               .initial = 0;
+       }
+
+       backend b1 {
+               .host = "${s1_addr}";
+               .port = "${s1_port}";
+               .max_connections = 1;
+               .probe = p1;
+       }
+       backend b2 {
+               .host = "${s2_addr}";
+               .port = "${s2_port}";
+               .max_connections = 1;
+               .probe = p2;
+       }
+       backend b3 {
+               .host = "${s3_addr}";
+               .port = "${s3_port}";
+       }
+       director f1 fallback {
+               { .backend = b1; }
+               { .backend = b2; }
+               { .backend = b3; }
+       }
+
+       sub vcl_recv {
+               set req.backend = f1;
+               return(pass);
+       }
+} -start
+
+# s1 & s2 have both had 1 probe, so both are unhealthy
+
+client c1 {
+       txreq -url "/foo"
+       rxresp
+       expect resp.http.foo == "3"
+} -run
+
+# setup for probe #2
+
+server s1 {
+       rxreq
+       expect req.url == "/"
+       txresp -body "slash"
+} -start
+
+server s2 {
+       rxreq
+       expect req.url == "/"
+       txresp -body "slash"
+} -start
+
+# if we muck with a running server, the test will wait until it's done,
+# which will be after probe #2 completes. b2 will then be healthy.
+
+server s2 {
+       rxreq
+       expect req.url == "/foo"
+       txresp -hdr "Foo: 2" -body "foobar"
+} -start
+
+client c1 {
+       txreq -url "/foo"
+       rxresp
+       expect resp.http.foo == "2"
+} -run
+
+# setup for probe #3
+
+server s1 {
+        rxreq
+        expect req.url == "/"
+        txresp -body "slash"
+} -start
+
+server s2 {
+        rxreq
+        expect req.url == "/"
+        txresp -body "slash"
+} -start
+
+# after probe #3 b1 should be healthy.
+
+server s1 {
+       rxreq
+       expect req.url == "/foo"
+       txresp -hdr "Foo: 1" -body "foobar"
+} -start
+
+client c1 {
+       txreq -url "/foo"
+       rxresp
+       expect resp.http.foo == "1"
+} -run
+
diff --git a/doc/sphinx/reference/vcl.rst b/doc/sphinx/reference/vcl.rst
index 281b653..4645cd1 100644
--- a/doc/sphinx/reference/vcl.rst
+++ b/doc/sphinx/reference/vcl.rst
@@ -221,6 +221,22 @@ The above example will append "internal.example.net" to 
the incoming Host
 header supplied by the client, before looking it up. All settings are
 optional.
 
+The fallback director
+~~~~~~~~~~~~~~~~~~~~~
+
+The fallback director will pick the first backend that is healthy. It 
+considers them in the order in which they are listed in its definition.
+
+The fallback director does not take any options.
+
+An example of a fallback director::
+
+  director b3 fallback {
+    { .backend = www1; }
+    { .backend = www2; } // will only be used if www1 is unhealthy.
+    { .backend = www3; } // will only be used if both www1 and www2
+                         // are unhealthy.
+  }
 
 Backend probes
 --------------
diff --git a/lib/libvcl/vcc_backend.c b/lib/libvcl/vcc_backend.c
index babfe01..b896a7d 100644
--- a/lib/libvcl/vcc_backend.c
+++ b/lib/libvcl/vcc_backend.c
@@ -695,6 +695,7 @@ static const struct dirlist {
        { "random",             vcc_ParseRandomDirector },
        { "client",             vcc_ParseRandomDirector },
        { "round-robin",        vcc_ParseRoundRobinDirector },
+       { "fallback",           vcc_ParseRoundRobinDirector },
        { "dns",                vcc_ParseDnsDirector },
        { NULL,         NULL }
 };
_______________________________________________
varnish-dev mailing list
[email protected]
https://www.varnish-cache.org/lists/mailman/listinfo/varnish-dev

Reply via email to