From 67b91e534e1a182be9c383c6bd4a36148c76fbec Mon Sep 17 00:00:00 2001 From: guscarreon Date: Thu, 10 Nov 2022 14:23:31 -0500 Subject: [PATCH] Make Aerospike connection idle timeout configurable (#118) --- backends/aerospike.go | 7 ++++++ backends/config/config.go | 4 ++-- backends/config/config_test.go | 6 ++--- config/backends.go | 20 ++++++++++++---- config/backends_test.go | 28 +++++++++++++++++++---- config/config.go | 1 + config/config_test.go | 17 +++++++------- config/configtest/sample_full_config.yaml | 1 + 8 files changed, 62 insertions(+), 22 deletions(-) diff --git a/backends/aerospike.go b/backends/aerospike.go index 9b37c4d4..00468459 100644 --- a/backends/aerospike.go +++ b/backends/aerospike.go @@ -3,6 +3,7 @@ package backends import ( "context" "errors" + "time" as "github.com/aerospike/aerospike-client-go/v6" as_types "github.com/aerospike/aerospike-client-go/v6/types" @@ -61,6 +62,12 @@ func NewAerospikeBackend(cfg config.Aerospike, metrics *metrics.Metrics) *Aerosp clientPolicy.User = cfg.User clientPolicy.Password = cfg.Password + // Aerospike's connection idle deadline default is 55 seconds. If greater than zero, this + // value will override + if cfg.ConnIdleTimeoutSecs > 0 { + clientPolicy.IdleTimeout = time.Duration(cfg.ConnIdleTimeoutSecs) * time.Second + } + if len(cfg.Host) > 1 { hosts = append(hosts, as.NewHost(cfg.Host, cfg.Port)) log.Info("config.backend.aerospike.host is being deprecated in favor of config.backend.aerospike.hosts") diff --git a/backends/config/config.go b/backends/config/config.go index 7d9cf47d..8bcf20bd 100644 --- a/backends/config/config.go +++ b/backends/config/config.go @@ -84,8 +84,8 @@ func getMaxTTLSeconds(cfg config.Configuration) int { case config.BackendAerospike: // If both config.request_limits.max_ttl_seconds and config.backend.aerospike.default_ttl_seconds // were defined, the smallest value takes preference - if cfg.Backend.Aerospike.DefaultTTL > 0 && maxTTLSeconds > cfg.Backend.Aerospike.DefaultTTL { - maxTTLSeconds = cfg.Backend.Aerospike.DefaultTTL + if cfg.Backend.Aerospike.DefaultTTLSecs > 0 && maxTTLSeconds > cfg.Backend.Aerospike.DefaultTTLSecs { + maxTTLSeconds = cfg.Backend.Aerospike.DefaultTTLSecs } case config.BackendRedis: // If both config.request_limits.max_ttl_seconds and backend.redis.expiration diff --git a/backends/config/config_test.go b/backends/config/config_test.go index bab2f919..e058bb7a 100644 --- a/backends/config/config_test.go +++ b/backends/config/config_test.go @@ -233,7 +233,7 @@ func TestGetMaxTTLSeconds(t *testing.T) { Backend: config.Backend{ Type: config.BackendAerospike, Aerospike: config.Aerospike{ - DefaultTTL: 0, + DefaultTTLSecs: 0, }, }, RequestLimits: config.RequestLimits{ @@ -248,7 +248,7 @@ func TestGetMaxTTLSeconds(t *testing.T) { Backend: config.Backend{ Type: config.BackendAerospike, Aerospike: config.Aerospike{ - DefaultTTL: 100, + DefaultTTLSecs: 100, }, }, RequestLimits: config.RequestLimits{ @@ -263,7 +263,7 @@ func TestGetMaxTTLSeconds(t *testing.T) { Backend: config.Backend{ Type: config.BackendAerospike, Aerospike: config.Aerospike{ - DefaultTTL: 1, + DefaultTTLSecs: 1, }, }, RequestLimits: config.RequestLimits{ diff --git a/config/backends.go b/config/backends.go index b7969029..93718976 100644 --- a/config/backends.go +++ b/config/backends.go @@ -45,7 +45,7 @@ const ( ) type Aerospike struct { - DefaultTTL int `mapstructure:"default_ttl_seconds"` + DefaultTTLSecs int `mapstructure:"default_ttl_seconds"` Host string `mapstructure:"host"` Hosts []string `mapstructure:"hosts"` Port int `mapstructure:"port"` @@ -54,6 +54,12 @@ type Aerospike struct { Password string `mapstructure:"password"` MaxReadRetries int `mapstructure:"max_read_retries"` MaxWriteRetries int `mapstructure:"max_write_retries"` + // Please set this to a value lower than the `proto-fd-idle-ms` (converted + // to seconds) value set in your Aerospike Server. This is to avoid having + // race conditions where the server closes the connection but the client still + // tries to use it. If set to a value less than or equal to 0, Aerospike + // Client's default value will be used which is 55 seconds. + ConnIdleTimeoutSecs int `mapstructure:"connection_idle_timeout_seconds"` } func (cfg *Aerospike) validateAndLog() error { @@ -64,15 +70,21 @@ func (cfg *Aerospike) validateAndLog() error { if cfg.Port <= 0 { return fmt.Errorf("Cannot connect to Aerospike host at port %d", cfg.Port) } - if cfg.DefaultTTL > 0 { - log.Infof("config.backend.aerospike.default_ttl_seconds: %d. Note that this configuration option is being deprecated in favor of config.request_limits.max_ttl_seconds", cfg.DefaultTTL) - } + log.Infof("config.backend.aerospike.host: %s", cfg.Host) log.Infof("config.backend.aerospike.hosts: %v", cfg.Hosts) log.Infof("config.backend.aerospike.port: %d", cfg.Port) log.Infof("config.backend.aerospike.namespace: %s", cfg.Namespace) log.Infof("config.backend.aerospike.user: %s", cfg.User) + if cfg.DefaultTTLSecs > 0 { + log.Infof("config.backend.aerospike.default_ttl_seconds: %d. Note that this configuration option is being deprecated in favor of config.request_limits.max_ttl_seconds", cfg.DefaultTTLSecs) + } + + if cfg.ConnIdleTimeoutSecs > 0 { + log.Infof("config.backend.aerospike.connection_idle_timeout_seconds: %d.", cfg.ConnIdleTimeoutSecs) + } + if cfg.MaxReadRetries < 2 { log.Infof("config.backend.aerospike.max_read_retries value will default to 2") cfg.MaxReadRetries = 2 diff --git a/config/backends_test.go b/config/backends_test.go index 57c1b3ba..fe8b4bf4 100644 --- a/config/backends_test.go +++ b/config/backends_test.go @@ -100,19 +100,19 @@ func TestAerospikeValidateAndLog(t *testing.T) { { desc: "both aerospike.host, aerospike.hosts and aerospike.default_ttl_seconds set", inCfg: Aerospike{ - Host: "foo.com", - Hosts: []string{"foo.com", "bat.com"}, - Port: 8888, - DefaultTTL: 3600, + Host: "foo.com", + Hosts: []string{"foo.com", "bat.com"}, + Port: 8888, + DefaultTTLSecs: 3600, }, hasError: false, logEntries: []logComponents{ - {msg: "config.backend.aerospike.default_ttl_seconds: 3600. Note that this configuration option is being deprecated in favor of config.request_limits.max_ttl_seconds", lvl: logrus.InfoLevel}, {msg: "config.backend.aerospike.host: foo.com", lvl: logrus.InfoLevel}, {msg: fmt.Sprintf("config.backend.aerospike.hosts: %v", []string{"foo.com", "bat.com"}), lvl: logrus.InfoLevel}, {msg: "config.backend.aerospike.port: 8888", lvl: logrus.InfoLevel}, {msg: "config.backend.aerospike.namespace: ", lvl: logrus.InfoLevel}, {msg: "config.backend.aerospike.user: ", lvl: logrus.InfoLevel}, + {msg: "config.backend.aerospike.default_ttl_seconds: 3600. Note that this configuration option is being deprecated in favor of config.request_limits.max_ttl_seconds", lvl: logrus.InfoLevel}, {msg: "config.backend.aerospike.max_read_retries value will default to 2", lvl: logrus.InfoLevel}, }, }, @@ -186,6 +186,24 @@ func TestAerospikeValidateAndLog(t *testing.T) { {msg: "config.backend.aerospike.max_write_retries: 1.", lvl: logrus.InfoLevel}, }, }, + { + desc: "aerospike.connection_idle_timeout_seconds value found in config", + inCfg: Aerospike{ + Host: "foo.com", + Port: 8888, + ConnIdleTimeoutSecs: 1, + }, + hasError: false, + logEntries: []logComponents{ + {msg: "config.backend.aerospike.host: foo.com", lvl: logrus.InfoLevel}, + {msg: fmt.Sprintf("config.backend.aerospike.hosts: %v", []string{}), lvl: logrus.InfoLevel}, + {msg: "config.backend.aerospike.port: 8888", lvl: logrus.InfoLevel}, + {msg: "config.backend.aerospike.namespace: ", lvl: logrus.InfoLevel}, + {msg: "config.backend.aerospike.user: ", lvl: logrus.InfoLevel}, + {msg: "config.backend.aerospike.connection_idle_timeout_seconds: 1.", lvl: logrus.InfoLevel}, + {msg: "config.backend.aerospike.max_read_retries value will default to 2", lvl: logrus.InfoLevel}, + }, + }, }, }, { diff --git a/config/config.go b/config/config.go index 9ac095e2..95d64a76 100644 --- a/config/config.go +++ b/config/config.go @@ -55,6 +55,7 @@ func setConfigDefaults(v *viper.Viper) { v.SetDefault("backend.aerospike.default_ttl_seconds", 0) v.SetDefault("backend.aerospike.max_read_retries", 2) v.SetDefault("backend.aerospike.max_write_retries", 0) + v.SetDefault("backend.aerospike.connection_idle_timeout_seconds", 0) v.SetDefault("backend.cassandra.hosts", "") v.SetDefault("backend.cassandra.keyspace", "") v.SetDefault("backend.cassandra.default_ttl_seconds", utils.CASSANDRA_DEFAULT_TTL_SECONDS) diff --git a/config/config_test.go b/config/config_test.go index d8b9c77f..28578b68 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -1245,14 +1245,15 @@ func getExpectedFullConfigForTestFile() Configuration { Backend: Backend{ Type: BackendMemory, Aerospike: Aerospike{ - DefaultTTL: 3600, - Host: "aerospike.prebid.com", - Hosts: []string{"aerospike2.prebid.com", "aerospike3.prebid.com"}, - Port: 3000, - Namespace: "whatever", - User: "foo", - Password: "bar", - MaxReadRetries: 2, + DefaultTTLSecs: 3600, + Host: "aerospike.prebid.com", + Hosts: []string{"aerospike2.prebid.com", "aerospike3.prebid.com"}, + Port: 3000, + Namespace: "whatever", + User: "foo", + Password: "bar", + MaxReadRetries: 2, + ConnIdleTimeoutSecs: 2, }, Cassandra: Cassandra{ Hosts: "127.0.0.1", diff --git a/config/configtest/sample_full_config.yaml b/config/configtest/sample_full_config.yaml index 0f1454ee..6c298d59 100644 --- a/config/configtest/sample_full_config.yaml +++ b/config/configtest/sample_full_config.yaml @@ -21,6 +21,7 @@ backend: namespace: "whatever" user: "foo" password: "bar" + connection_idle_timeout_seconds: 2 cassandra: hosts: "127.0.0.1" keyspace: "prebid"