diff --git a/command/agent/config.go b/command/agent/config.go index 4d038df892..f7f296a542 100644 --- a/command/agent/config.go +++ b/command/agent/config.go @@ -173,6 +173,14 @@ type Config struct { // true, we ignore the leave, and rejoin the cluster on start. RejoinAfterLeave bool `mapstructure:"rejoin_after_leave"` + // CheckUpdateInterval controls the interval on which the output of a health check + // is updated if there is no change to the state. For example, a check in a steady + // state may run every 5 second generating a unique output (timestamp, etc), forcing + // constant writes. This allows Consul to defer the write for some period of time, + // reducing the write pressure when the state is steady. + CheckUpdateInterval time.Duration `mapstructure:"-"` + CheckUpdateIntervalRaw string `mapstructure:"check_update_interval" json:"-"` + // AEInterval controls the anti-entropy interval. This is how often // the agent attempts to reconcile it's local state with the server' // representation of our state. Defaults to every 60s. @@ -220,8 +228,9 @@ func DefaultConfig() *Config { DNSConfig: DNSConfig{ MaxStale: 5 * time.Second, }, - Protocol: consul.ProtocolVersionMax, - AEInterval: time.Minute, + Protocol: consul.ProtocolVersionMax, + CheckUpdateInterval: 5 * time.Minute, + AEInterval: time.Minute, } } @@ -309,6 +318,14 @@ func DecodeConfig(r io.Reader) (*Config, error) { } } + if raw := result.CheckUpdateIntervalRaw; raw != "" { + dur, err := time.ParseDuration(raw) + if err != nil { + return nil, fmt.Errorf("CheckUpdateInterval invalid: %v", err) + } + result.CheckUpdateInterval = dur + } + return &result, nil } @@ -536,6 +553,9 @@ func MergeConfig(a, b *Config) *Config { if b.DNSConfig.MaxStale != 0 { result.DNSConfig.MaxStale = b.DNSConfig.MaxStale } + if b.CheckUpdateInterval != 0 { + result.CheckUpdateInterval = b.CheckUpdateInterval + } // Copy the start join addresses result.StartJoin = make([]string, 0, len(a.StartJoin)+len(b.StartJoin)) diff --git a/command/agent/config_test.go b/command/agent/config_test.go index 767b17cf53..b1e2ef4c28 100644 --- a/command/agent/config_test.go +++ b/command/agent/config_test.go @@ -324,6 +324,17 @@ func TestDecodeConfig(t *testing.T) { if config.DNSConfig.ServiceTTL["web"] != 30*time.Second { t.Fatalf("bad: %#v", config) } + + // CheckUpdateInterval + input = `{"check_update_interval": "10m"}` + config, err = DecodeConfig(bytes.NewReader([]byte(input))) + if err != nil { + t.Fatalf("err: %s", err) + } + + if config.CheckUpdateInterval != 10*time.Minute { + t.Fatalf("bad: %#v", config) + } } func TestDecodeConfig_Service(t *testing.T) { @@ -451,21 +462,22 @@ func TestMergeConfig(t *testing.T) { SerfWan: 5, Server: 6, }, - Server: true, - LeaveOnTerm: true, - SkipLeaveOnInt: true, - EnableDebug: true, - VerifyIncoming: true, - VerifyOutgoing: true, - CAFile: "test/ca.pem", - CertFile: "test/cert.pem", - KeyFile: "test/key.pem", - Checks: []*CheckDefinition{nil}, - Services: []*ServiceDefinition{nil}, - StartJoin: []string{"1.1.1.1"}, - UiDir: "/opt/consul-ui", - EnableSyslog: true, - RejoinAfterLeave: true, + Server: true, + LeaveOnTerm: true, + SkipLeaveOnInt: true, + EnableDebug: true, + VerifyIncoming: true, + VerifyOutgoing: true, + CAFile: "test/ca.pem", + CertFile: "test/cert.pem", + KeyFile: "test/key.pem", + Checks: []*CheckDefinition{nil}, + Services: []*ServiceDefinition{nil}, + StartJoin: []string{"1.1.1.1"}, + UiDir: "/opt/consul-ui", + EnableSyslog: true, + RejoinAfterLeave: true, + CheckUpdateInterval: 8 * time.Minute, } c := MergeConfig(a, b)