From 6bda2c007ca9e1d4f8c5dc60fbb711eac5a00443 Mon Sep 17 00:00:00 2001 From: Sean Chittenden Date: Fri, 19 Feb 2016 00:27:39 -0800 Subject: [PATCH] Add a flag to denote that a server is disabled A server is not normally disabled, but in the event of an RPC error, we want to mark a server as down to allow for fast failover to a different server. This value must be an int in order to support atomic operations. Additionally, this is the preliminary work required to bring up a server in a disabled state. RPC health checks in the future could mark the server as alive, thereby creating an organic "slow start" feature for Consul. --- consul/util.go | 17 ++++++++++++++--- consul/util_test.go | 13 ++++++++++++- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/consul/util.go b/consul/util.go index 8959ee66a..d5b4573ba 100644 --- a/consul/util.go +++ b/consul/util.go @@ -23,7 +23,7 @@ import ( */ var privateBlocks []*net.IPNet -// serverparts is used to return the parts of a server role +// serverParts is used to return the parts of a server role type serverParts struct { Name string Datacenter string @@ -32,6 +32,11 @@ type serverParts struct { Expect int Version int Addr net.Addr + + // Disabled is a uint64 in order to support atomic integer + // operations. Zero means enabled, non-zero is the number of times + // this server has failed without being marked healthy. + Disabled uint64 } func (s *serverParts) String() string { @@ -116,8 +121,8 @@ func CanServersUnderstandProtocol(members []serf.Member, version uint8) (bool, e return (numServers > 0) && (numWhoGrok == numServers), nil } -// Returns if a member is a consul server. Returns a bool, -// the datacenter, and the rpc port +// Returns true if a serf member is a consul server. Returns a bool and a +// pointer to the serverParts. func isConsulServer(m serf.Member) (bool, *serverParts) { if m.Tags["role"] != "consul" { return false, nil @@ -125,6 +130,11 @@ func isConsulServer(m serf.Member) (bool, *serverParts) { datacenter := m.Tags["dc"] _, bootstrap := m.Tags["bootstrap"] + var disabled uint64 = 0 + _, disabledStr := m.Tags["disabled"] + if disabledStr { + disabled = 1 + } expect := 0 expect_str, ok := m.Tags["expect"] @@ -158,6 +168,7 @@ func isConsulServer(m serf.Member) (bool, *serverParts) { Expect: expect, Addr: addr, Version: vsn, + Disabled: disabled, } return true, parts } diff --git a/consul/util_test.go b/consul/util_test.go index 1011ec896..f2b868d33 100644 --- a/consul/util_test.go +++ b/consul/util_test.go @@ -217,14 +217,24 @@ func TestIsConsulServer(t *testing.T) { if parts.Bootstrap { t.Fatalf("unexpected bootstrap") } + if parts.Disabled > 0 { + t.Fatalf("unexpected disabled") + } if parts.Expect != 0 { t.Fatalf("bad: %v", parts.Expect) } m.Tags["bootstrap"] = "1" + m.Tags["disabled"] = "1" valid, parts = isConsulServer(m) - if !valid || !parts.Bootstrap { + if !valid { + t.Fatalf("expected a valid consul server") + } + if !parts.Bootstrap { t.Fatalf("expected bootstrap") } + if parts.Disabled == 0 { + t.Fatalf("expected disabled") + } if parts.Addr.String() != "127.0.0.1:10000" { t.Fatalf("bad addr: %v", parts.Addr) } @@ -233,6 +243,7 @@ func TestIsConsulServer(t *testing.T) { } m.Tags["expect"] = "3" delete(m.Tags, "bootstrap") + delete(m.Tags, "disabled") valid, parts = isConsulServer(m) if !valid || parts.Expect != 3 { t.Fatalf("bad: %v", parts.Expect)