From 6a614f832e35b1a3996d2e895a0dda5561b61725 Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez Date: Sat, 8 Apr 2023 18:33:55 -0700 Subject: [PATCH 01/11] Support for Redis Sentinel Client --- redis/README.md | 59 ++++++++++++++++++++++++++++++++++++++------- redis/config.go | 56 +++++++++++++++++++++++++++++++++++------- redis/redis.go | 19 ++++++++++++--- redis/redis_test.go | 28 +++++++++++++++++++++ 4 files changed, 141 insertions(+), 21 deletions(-) diff --git a/redis/README.md b/redis/README.md index 0c690303..8f58f13d 100644 --- a/redis/README.md +++ b/redis/README.md @@ -53,6 +53,16 @@ store := redis.New(redis.Config{ PoolSize: 10 * runtime.GOMAXPROCS(0), }) +// Initialize Redis Sentinel Server Client +store := redis.New(redis.Config{ + EnableFailover: true, + MasterName: "master-name", + SentinelHosts: []string{":6379", ":6380", ":6381"}, + ClientName: "", + SentinelUsername: "", + SentinelPassword: "", +}) + // or just the url with all information store = redis.New(redis.Config{ URL: "redis://:@127.0.0.1:6379/", @@ -108,6 +118,31 @@ type Config struct { // // Optional. Default is 10 connections per every available CPU as reported by runtime.GOMAXPROCS. PoolSize int + + // EnableFailover to use redis FailoverClient with Sentinel instead of the standard redis Client + // + // Optional. Default is false + EnableFailover bool + + // MasterName is the sentinel master's name + // + // Optional. Default is "" + MasterName string + + // SentinelHosts where the Redis Sentinel is hosted + // + // Optional. Default is []string{} + SentinelHosts []string + + // SentinelUsername + // + // Optional. Default is "" + SentinelUsername string + + // SentinelPassword + // + // Optional. Default is "" + SentinelPassword string } ``` @@ -115,14 +150,20 @@ type Config struct { ### Default Config ```go var ConfigDefault = Config{ - Host: "127.0.0.1", - Port: 6379, - Username: "", - Password: "", - URL: "", - Database: 0, - Reset: false, - TLSConfig: nil, - PoolSize: 10 * runtime.GOMAXPROCS(0), + Host: "127.0.0.1", + Port: 6379, + Username: "", + Password: "", + URL: "", + Database: 0, + Reset: false, + TLSConfig: nil, + PoolSize: 10 * runtime.GOMAXPROCS(0), + EnableFailover: false, + MasterName: "", + SentinelHosts: []string{}, + ClientName: "", + SentinelUsername: "", + SentinelPassword: "", } ``` diff --git a/redis/config.go b/redis/config.go index c154678f..bfb19c9a 100644 --- a/redis/config.go +++ b/redis/config.go @@ -38,12 +38,44 @@ type Config struct { // Optional. Default is "" URL string + // EnableFailover to use redis FailoverClient with Sentinel instead of the standard redis Client + // + // Optional. Default is false + EnableFailover bool + + // SentinelHosts where the Redis Sentinel is hosted + // + // Optional. Default is []string{} + SentinelHosts []string + + // MasterName is the sentinel master's name + // + // Optional. Default is "" + MasterName string + + // ClientName will execute the `CLIENT SETNAME ClientName` command for each sentinel conn. + // + // Optional. Default is "" + ClientName string + + // SentinelUsername + // + // Optional. Default is "" + SentinelUsername string + + // SentinelPassword + // + // Optional. Default is "" + SentinelPassword string + // Reset clears any existing keys in existing Collection // // Optional. Default is false Reset bool // TLS Config to use. When set TLS will be negotiated. + // + // Optional. Default is nil TLSConfig *tls.Config // Maximum number of socket connections. @@ -60,15 +92,21 @@ type Config struct { // ConfigDefault is the default config var ConfigDefault = Config{ - Host: "127.0.0.1", - Port: 6379, - Username: "", - Password: "", - URL: "", - Database: 0, - Reset: false, - TLSConfig: nil, - PoolSize: 10 * runtime.GOMAXPROCS(0), + Host: "127.0.0.1", + Port: 6379, + Username: "", + Password: "", + URL: "", + Database: 0, + Reset: false, + TLSConfig: nil, + PoolSize: 10 * runtime.GOMAXPROCS(0), + EnableFailover: false, + MasterName: "", + SentinelHosts: []string{}, + ClientName: "", + SentinelUsername: "", + SentinelPassword: "", } // Helper function to set default values diff --git a/redis/redis.go b/redis/redis.go index c584417c..d8d53070 100644 --- a/redis/redis.go +++ b/redis/redis.go @@ -22,7 +22,7 @@ func New(config ...Config) *Storage { var options *redis.Options var err error - if cfg.URL != "" { + if cfg.URL != "" && !cfg.EnableFailover { options, err = redis.ParseURL(cfg.URL) if err != nil { @@ -31,6 +31,20 @@ func New(config ...Config) *Storage { options.TLSConfig = cfg.TLSConfig options.PoolSize = cfg.PoolSize + db = redis.NewClient(options) + } else if cfg.EnableFailover { + options = &redis.FailoverOptions{ + MasterName: cfg.MasterName, + SentinelAddrs: cfg.SentinelHosts, + ClientName: cfg.ClientName, + SentinelUsername: cfg.SentinelUsername, + SentinelPassword: cfg.SentinelPassword, + DB: cfg.Database, + Password: cfg.Password, + TLSConfig: cfg.TLSConfig, + PoolSize: cfg.PoolSize, + } + db = redis.NewFailoverClient(options) } else { options = &redis.Options{ Addr: fmt.Sprintf("%s:%d", cfg.Host, cfg.Port), @@ -40,10 +54,9 @@ func New(config ...Config) *Storage { TLSConfig: cfg.TLSConfig, PoolSize: cfg.PoolSize, } + db := redis.NewClient(options) } - db := redis.NewClient(options) - // Test connection if err := db.Ping(context.Background()).Err(); err != nil { panic(err) diff --git a/redis/redis_test.go b/redis/redis_test.go index 567d4ea6..409ecc0f 100644 --- a/redis/redis_test.go +++ b/redis/redis_test.go @@ -191,3 +191,31 @@ func Test_Redis_Initalize_WithURL_TLS(t *testing.T) { utils.AssertEqual(t, nil, testStoreUrl.Close()) } + +func Test_Redis_Sentinel(t *testing.T) { + testStoreSentinel := New(Config{ + EnableFailover: true, + MasterName: "", + SentinelHosts: []string{"localhost:6379"}, + ClientName: "", + SentinelUsername: "", + SentinelPassword: "", + }) + + var ( + key = "bruce" + val = []byte("wayne") + ) + + err := testStoreSentinel.Set(key, val, 0) + utils.AssertEqual(t, nil, err) + + result, err := testStoreSentinel.Get(key) + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, val, result) + + err = testStoreSentinel.Delete(key) + utils.AssertEqual(t, nil, err) + + utils.AssertEqual(t, nil, testStoreSentinel.Close()) +} From ca239f0353faacde1a22543b62b35ace7a66a583 Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez Date: Sat, 8 Apr 2023 18:41:29 -0700 Subject: [PATCH 02/11] Fix syntax issues --- redis/redis.go | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/redis/redis.go b/redis/redis.go index d8d53070..a32866ef 100644 --- a/redis/redis.go +++ b/redis/redis.go @@ -19,11 +19,8 @@ func New(config ...Config) *Storage { cfg := configDefault(config...) // Create new redis client - var options *redis.Options - var err error - if cfg.URL != "" && !cfg.EnableFailover { - options, err = redis.ParseURL(cfg.URL) + options, err := redis.ParseURL(cfg.URL) if err != nil { panic(err) @@ -31,9 +28,9 @@ func New(config ...Config) *Storage { options.TLSConfig = cfg.TLSConfig options.PoolSize = cfg.PoolSize - db = redis.NewClient(options) + db := redis.NewClient(options) } else if cfg.EnableFailover { - options = &redis.FailoverOptions{ + options := &redis.FailoverOptions{ MasterName: cfg.MasterName, SentinelAddrs: cfg.SentinelHosts, ClientName: cfg.ClientName, @@ -44,9 +41,9 @@ func New(config ...Config) *Storage { TLSConfig: cfg.TLSConfig, PoolSize: cfg.PoolSize, } - db = redis.NewFailoverClient(options) + db := redis.NewFailoverClient(options) } else { - options = &redis.Options{ + options := &redis.Options{ Addr: fmt.Sprintf("%s:%d", cfg.Host, cfg.Port), DB: cfg.Database, Username: cfg.Username, From 5a120d680733883e2080b9f01b039255ed98f69e Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez Date: Sat, 8 Apr 2023 18:42:55 -0700 Subject: [PATCH 03/11] Simplify logic of New function --- redis/redis.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/redis/redis.go b/redis/redis.go index a32866ef..46da8e29 100644 --- a/redis/redis.go +++ b/redis/redis.go @@ -30,7 +30,7 @@ func New(config ...Config) *Storage { options.PoolSize = cfg.PoolSize db := redis.NewClient(options) } else if cfg.EnableFailover { - options := &redis.FailoverOptions{ + db := redis.NewFailoverClient(&redis.FailoverOptions{ MasterName: cfg.MasterName, SentinelAddrs: cfg.SentinelHosts, ClientName: cfg.ClientName, @@ -40,18 +40,16 @@ func New(config ...Config) *Storage { Password: cfg.Password, TLSConfig: cfg.TLSConfig, PoolSize: cfg.PoolSize, - } - db := redis.NewFailoverClient(options) + }) } else { - options := &redis.Options{ + db := redis.NewClient(&redis.Options{ Addr: fmt.Sprintf("%s:%d", cfg.Host, cfg.Port), DB: cfg.Database, Username: cfg.Username, Password: cfg.Password, TLSConfig: cfg.TLSConfig, PoolSize: cfg.PoolSize, - } - db := redis.NewClient(options) + }) } // Test connection From 7e6ede5392711ac4a62a8a07e8a7b92e751a76da Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez Date: Sat, 8 Apr 2023 18:49:01 -0700 Subject: [PATCH 04/11] Fix undefined var issues --- redis/redis.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/redis/redis.go b/redis/redis.go index 46da8e29..b60ab46d 100644 --- a/redis/redis.go +++ b/redis/redis.go @@ -19,6 +19,8 @@ func New(config ...Config) *Storage { cfg := configDefault(config...) // Create new redis client + var db *redis.Client + if cfg.URL != "" && !cfg.EnableFailover { options, err := redis.ParseURL(cfg.URL) @@ -28,9 +30,9 @@ func New(config ...Config) *Storage { options.TLSConfig = cfg.TLSConfig options.PoolSize = cfg.PoolSize - db := redis.NewClient(options) + db = redis.NewClient(options) } else if cfg.EnableFailover { - db := redis.NewFailoverClient(&redis.FailoverOptions{ + db = redis.NewFailoverClient(&redis.FailoverOptions{ MasterName: cfg.MasterName, SentinelAddrs: cfg.SentinelHosts, ClientName: cfg.ClientName, @@ -42,7 +44,7 @@ func New(config ...Config) *Storage { PoolSize: cfg.PoolSize, }) } else { - db := redis.NewClient(&redis.Options{ + db = redis.NewClient(&redis.Options{ Addr: fmt.Sprintf("%s:%d", cfg.Host, cfg.Port), DB: cfg.Database, Username: cfg.Username, From 22e48de898a0af03c2bd3652ecdca9fbf738826d Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez Date: Sun, 9 Apr 2023 21:04:52 -0700 Subject: [PATCH 05/11] Add support for Redis Universal Client --- redis/config.go | 48 +++++++++++++---------------------- redis/redis.go | 61 +++++++++++++++++++++------------------------ redis/redis_test.go | 46 +++++++++++++++++++++++++--------- 3 files changed, 81 insertions(+), 74 deletions(-) diff --git a/redis/config.go b/redis/config.go index bfb19c9a..976bc6a9 100644 --- a/redis/config.go +++ b/redis/config.go @@ -32,28 +32,23 @@ type Config struct { // Optional. Default is 0 Database int - // URL the standard format redis url to parse all other options. If this is set all other config options, Host, Port, Username, Password, Database have no effect. + // URL standard format Redis URL. If this is set all other config options, Host, Port, Username, Password, Database have no effect. // // Example: redis://:@localhost:6379/ // Optional. Default is "" URL string - // EnableFailover to use redis FailoverClient with Sentinel instead of the standard redis Client - // - // Optional. Default is false - EnableFailover bool - - // SentinelHosts where the Redis Sentinel is hosted + // Either a single address or a seed list of host:port addresses, this enables FailoverClient and ClusterClient // // Optional. Default is []string{} - SentinelHosts []string + Addrs []string // MasterName is the sentinel master's name // // Optional. Default is "" MasterName string - // ClientName will execute the `CLIENT SETNAME ClientName` command for each sentinel conn. + // ClientName will execute the `CLIENT SETNAME ClientName` command for each conn. // // Optional. Default is "" ClientName string @@ -82,31 +77,24 @@ type Config struct { // // Optional. Default is 10 connections per every available CPU as reported by runtime.GOMAXPROCS. PoolSize int - - //////////////////////////////////// - // Adaptor related config options // - //////////////////////////////////// - - // https://pkg.go.dev/github.com/go-redis/redis/v8#Options } // ConfigDefault is the default config var ConfigDefault = Config{ - Host: "127.0.0.1", - Port: 6379, - Username: "", - Password: "", - URL: "", - Database: 0, - Reset: false, - TLSConfig: nil, - PoolSize: 10 * runtime.GOMAXPROCS(0), - EnableFailover: false, - MasterName: "", - SentinelHosts: []string{}, - ClientName: "", - SentinelUsername: "", - SentinelPassword: "", + Host: "127.0.0.1", + Port: 6379, + Username: "", + Password: "", + URL: "", + Database: 0, + Reset: false, + TLSConfig: nil, + PoolSize: 10 * runtime.GOMAXPROCS(0), + Addrs: []string{}, + MasterName: "", + ClientName: "", + SentinelUsername: "", + SentinelPassword: "", } // Helper function to set default values diff --git a/redis/redis.go b/redis/redis.go index b60ab46d..ec555a06 100644 --- a/redis/redis.go +++ b/redis/redis.go @@ -10,7 +10,7 @@ import ( // Storage interface that is implemented by storage providers type Storage struct { - db *redis.Client + db redis.UniversalClient } // New creates a new redis storage @@ -18,42 +18,39 @@ func New(config ...Config) *Storage { // Set default config cfg := configDefault(config...) - // Create new redis client - var db *redis.Client + // Create new redis universal client + var db redis.UniversalClient - if cfg.URL != "" && !cfg.EnableFailover { + // Parse the URL and update config values accordingly + if cfg.URL != "" { options, err := redis.ParseURL(cfg.URL) - if err != nil { panic(err) } - options.TLSConfig = cfg.TLSConfig - options.PoolSize = cfg.PoolSize - db = redis.NewClient(options) - } else if cfg.EnableFailover { - db = redis.NewFailoverClient(&redis.FailoverOptions{ - MasterName: cfg.MasterName, - SentinelAddrs: cfg.SentinelHosts, - ClientName: cfg.ClientName, - SentinelUsername: cfg.SentinelUsername, - SentinelPassword: cfg.SentinelPassword, - DB: cfg.Database, - Password: cfg.Password, - TLSConfig: cfg.TLSConfig, - PoolSize: cfg.PoolSize, - }) - } else { - db = redis.NewClient(&redis.Options{ - Addr: fmt.Sprintf("%s:%d", cfg.Host, cfg.Port), - DB: cfg.Database, - Username: cfg.Username, - Password: cfg.Password, - TLSConfig: cfg.TLSConfig, - PoolSize: cfg.PoolSize, - }) + // Update the config values with the parsed URL values + cfg.Username = options.Username + cfg.Password = options.Password + cfg.Database = options.DB + cfg.Addrs = []string{options.Addr} + } else if len(cfg.Addrs) == 0 { + // Fallback to Host and Port values if Addrs is empty + cfg.Addrs = []string{fmt.Sprintf("%s:%d", cfg.Host, cfg.Port)} } + db = redis.NewUniversalClient(&redis.UniversalOptions{ + Addrs: cfg.Addrs, + MasterName: cfg.MasterName, + ClientName: cfg.ClientName, + SentinelUsername: cfg.SentinelUsername, + SentinelPassword: cfg.SentinelPassword, + DB: cfg.Database, + Username: cfg.Username, + Password: cfg.Password, + TLSConfig: cfg.TLSConfig, + PoolSize: cfg.PoolSize, + }) + // Test connection if err := db.Ping(context.Background()).Err(); err != nil { panic(err) @@ -72,6 +69,8 @@ func New(config ...Config) *Storage { } } +// ... + // Get value by key func (s *Storage) Get(key string) ([]byte, error) { if len(key) <= 0 { @@ -86,7 +85,6 @@ func (s *Storage) Get(key string) ([]byte, error) { // Set key with value func (s *Storage) Set(key string, val []byte, exp time.Duration) error { - // Ain't Nobody Got Time For That if len(key) <= 0 || len(val) <= 0 { return nil } @@ -95,7 +93,6 @@ func (s *Storage) Set(key string, val []byte, exp time.Duration) error { // Delete key by key func (s *Storage) Delete(key string) error { - // Ain't Nobody Got Time For That if len(key) <= 0 { return nil } @@ -113,6 +110,6 @@ func (s *Storage) Close() error { } // Return database client -func (s *Storage) Conn() *redis.Client { +func (s *Storage) Conn() redis.UniversalClient { return s.db } diff --git a/redis/redis_test.go b/redis/redis_test.go index 409ecc0f..a357475d 100644 --- a/redis/redis_test.go +++ b/redis/redis_test.go @@ -192,14 +192,10 @@ func Test_Redis_Initalize_WithURL_TLS(t *testing.T) { utils.AssertEqual(t, nil, testStoreUrl.Close()) } -func Test_Redis_Sentinel(t *testing.T) { - testStoreSentinel := New(Config{ - EnableFailover: true, - MasterName: "", - SentinelHosts: []string{"localhost:6379"}, - ClientName: "", - SentinelUsername: "", - SentinelPassword: "", +func Test_Redis_Universal(t *testing.T) { + // This should failover and create a Single Node connection. + testStoreUniversal := New(Config{ + Addrs: []string{"localhost:6379"}, }) var ( @@ -207,15 +203,41 @@ func Test_Redis_Sentinel(t *testing.T) { val = []byte("wayne") ) - err := testStoreSentinel.Set(key, val, 0) + err := testStoreUniversal.Set(key, val, 0) utils.AssertEqual(t, nil, err) - result, err := testStoreSentinel.Get(key) + result, err := testStoreUniversal.Get(key) utils.AssertEqual(t, nil, err) utils.AssertEqual(t, val, result) - err = testStoreSentinel.Delete(key) + err = testStoreUniversal.Delete(key) utils.AssertEqual(t, nil, err) - utils.AssertEqual(t, nil, testStoreSentinel.Close()) + utils.AssertEqual(t, nil, testStoreUniversal.Close()) +} + +func Test_Redis_Universal_With_URL(t *testing.T) { + // This should failover to creating a regular *redis.Client + // The URL should get ignored since EnableUniversalClient is enabled + testStoreUniversal := New(Config{ + URL: "", + Addrs: []string{"localhost:6379"}, + }) + + var ( + key = "bruce" + val = []byte("wayne") + ) + + err := testStoreUniversal.Set(key, val, 0) + utils.AssertEqual(t, nil, err) + + result, err := testStoreUniversal.Get(key) + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, val, result) + + err = testStoreUniversal.Delete(key) + utils.AssertEqual(t, nil, err) + + utils.AssertEqual(t, nil, testStoreUniversal.Close()) } From e3320c408476880a7471d53b1816995955f778e1 Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez Date: Sun, 9 Apr 2023 21:16:07 -0700 Subject: [PATCH 06/11] Expand unit-test to cover all config cases in New() --- redis/redis_test.go | 87 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 3 deletions(-) diff --git a/redis/redis_test.go b/redis/redis_test.go index a357475d..1ccc2ef5 100644 --- a/redis/redis_test.go +++ b/redis/redis_test.go @@ -192,7 +192,7 @@ func Test_Redis_Initalize_WithURL_TLS(t *testing.T) { utils.AssertEqual(t, nil, testStoreUrl.Close()) } -func Test_Redis_Universal(t *testing.T) { +func Test_Redis_Universal_Addrs(t *testing.T) { // This should failover and create a Single Node connection. testStoreUniversal := New(Config{ Addrs: []string{"localhost:6379"}, @@ -216,9 +216,9 @@ func Test_Redis_Universal(t *testing.T) { utils.AssertEqual(t, nil, testStoreUniversal.Close()) } -func Test_Redis_Universal_With_URL(t *testing.T) { +func Test_Redis_Universal_With_URL_Undefined(t *testing.T) { // This should failover to creating a regular *redis.Client - // The URL should get ignored since EnableUniversalClient is enabled + // The URL should get ignored since it's empty testStoreUniversal := New(Config{ URL: "", Addrs: []string{"localhost:6379"}, @@ -241,3 +241,84 @@ func Test_Redis_Universal_With_URL(t *testing.T) { utils.AssertEqual(t, nil, testStoreUniversal.Close()) } + +func Test_Redis_Universal_With_URL_Defined(t *testing.T) { + // This should failover to creating a regular *redis.Client + // The Addrs field should get ignored since URL is defined + testStoreUniversal := New(Config{ + URL: "redis://localhost:6379", + Addrs: []string{"localhost:6355"}, + }) + + var ( + key = "bruce" + val = []byte("wayne") + ) + + err := testStoreUniversal.Set(key, val, 0) + utils.AssertEqual(t, nil, err) + + result, err := testStoreUniversal.Get(key) + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, val, result) + + err = testStoreUniversal.Delete(key) + utils.AssertEqual(t, nil, err) + + utils.AssertEqual(t, nil, testStoreUniversal.Close()) +} + +func Test_Redis_Universal_With_HostPort(t *testing.T) { + // This should failover to creating a regular *redis.Client + // The Host and Port should get ignored since Addrs is defined + testStoreUniversal := New(Config{ + Host: "localhost", + Port: 6388, + Addrs: []string{"localhost:6379"}, + }) + + var ( + key = "bruce" + val = []byte("wayne") + ) + + err := testStoreUniversal.Set(key, val, 0) + utils.AssertEqual(t, nil, err) + + result, err := testStoreUniversal.Get(key) + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, val, result) + + err = testStoreUniversal.Delete(key) + utils.AssertEqual(t, nil, err) + + utils.AssertEqual(t, nil, testStoreUniversal.Close()) +} + +func Test_Redis_Universal_With_HostPort_And_URL(t *testing.T) { + // This should failover to creating a regular *redis.Client + // The Host and Port should get ignored since Addrs is defined + testStoreUniversal := New(Config{ + URL: "redis://localhost:6379", + Host: "localhost", + Port: 6388, + Addrs: []string{"localhost:6399"}, + }) + + var ( + key = "bruce" + val = []byte("wayne") + ) + + err := testStoreUniversal.Set(key, val, 0) + utils.AssertEqual(t, nil, err) + + result, err := testStoreUniversal.Get(key) + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, val, result) + + err = testStoreUniversal.Delete(key) + utils.AssertEqual(t, nil, err) + + utils.AssertEqual(t, nil, testStoreUniversal.Close()) +} From 78849085f05758602b7cfe612fb67939fe2abbf3 Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez Date: Sun, 9 Apr 2023 21:24:25 -0700 Subject: [PATCH 07/11] Update README and examples --- redis/README.md | 90 ++++++++++++++++++++++----------------------- redis/config.go | 28 +++++++------- redis/redis_test.go | 24 ++++++------ 3 files changed, 70 insertions(+), 72 deletions(-) diff --git a/redis/README.md b/redis/README.md index 8f58f13d..dbb1a058 100644 --- a/redis/README.md +++ b/redis/README.md @@ -17,7 +17,7 @@ func (s *Storage) Set(key string, val []byte, exp time.Duration) error func (s *Storage) Delete(key string) error func (s *Storage) Reset() error func (s *Storage) Close() error -func (s *Storage) Conn() *redis.Client +func (s *Storage) Conn() redis.UniversalClient ``` ### Installation Redis is tested on the 2 last [Go versions](https://golang.org/dl/) with support for modules. So make sure to initialize one first if you didn't do that yet: @@ -46,21 +46,21 @@ store := redis.New(redis.Config{ Port: 6379, Username: "", Password: "", - URL: "", Database: 0, Reset: false, TLSConfig: nil, PoolSize: 10 * runtime.GOMAXPROCS(0), }) -// Initialize Redis Sentinel Server Client +// Initialize Redis Failover Client store := redis.New(redis.Config{ - EnableFailover: true, MasterName: "master-name", - SentinelHosts: []string{":6379", ":6380", ":6381"}, - ClientName: "", - SentinelUsername: "", - SentinelPassword: "", + Addrs: []string{":6379"}, +}) + +// Initialize Redis Cluster Client +store := redis.New(redis.Config{ + Addrs: []string{":6379", ":6380"}, }) // or just the url with all information @@ -98,41 +98,26 @@ type Config struct { // Optional. Default is 0 Database int - // URL the standard format redis url to parse all other options. If this is set all other config options, Host, Port, Username, Password, Database have no effect. + // URL standard format Redis URL. If this is set all other config options, Host, Port, Username, Password, Database have no effect. // // Example: redis://:@localhost:6379/ // Optional. Default is "" URL string - // Reset clears any existing keys in existing Collection - // - // Optional. Default is false - Reset bool - - // TLS Config to use. When set TLS will be negotiated. + // Either a single address or a seed list of host:port addresses, this enables FailoverClient and ClusterClient // - // Optional. Default is nil - TLSConfig *tls.Config - - // Maximum number of socket connections. - // - // Optional. Default is 10 connections per every available CPU as reported by runtime.GOMAXPROCS. - PoolSize int - - // EnableFailover to use redis FailoverClient with Sentinel instead of the standard redis Client - // - // Optional. Default is false - EnableFailover bool + // Optional. Default is []string{} + Addrs []string // MasterName is the sentinel master's name // // Optional. Default is "" MasterName string - // SentinelHosts where the Redis Sentinel is hosted + // ClientName will execute the `CLIENT SETNAME ClientName` command for each conn. // - // Optional. Default is []string{} - SentinelHosts []string + // Optional. Default is "" + ClientName string // SentinelUsername // @@ -143,27 +128,40 @@ type Config struct { // // Optional. Default is "" SentinelPassword string -} + // Reset clears any existing keys in existing Collection + // + // Optional. Default is false + Reset bool + + // TLS Config to use. When set TLS will be negotiated. + // + // Optional. Default is nil + TLSConfig *tls.Config + + // Maximum number of socket connections. + // + // Optional. Default is 10 connections per every available CPU as reported by runtime.GOMAXPROCS. + PoolSize int +} ``` ### Default Config ```go var ConfigDefault = Config{ - Host: "127.0.0.1", - Port: 6379, - Username: "", - Password: "", - URL: "", - Database: 0, - Reset: false, - TLSConfig: nil, - PoolSize: 10 * runtime.GOMAXPROCS(0), - EnableFailover: false, - MasterName: "", - SentinelHosts: []string{}, - ClientName: "", - SentinelUsername: "", - SentinelPassword: "", + Host: "127.0.0.1", + Port: 6379, + Username: "", + Password: "", + URL: "", + Database: 0, + Reset: false, + TLSConfig: nil, + PoolSize: 10 * runtime.GOMAXPROCS(0), + Addrs: []string{}, + MasterName: "", + ClientName: "", + SentinelUsername: "", + SentinelPassword: "", } ``` diff --git a/redis/config.go b/redis/config.go index 976bc6a9..38212767 100644 --- a/redis/config.go +++ b/redis/config.go @@ -81,20 +81,20 @@ type Config struct { // ConfigDefault is the default config var ConfigDefault = Config{ - Host: "127.0.0.1", - Port: 6379, - Username: "", - Password: "", - URL: "", - Database: 0, - Reset: false, - TLSConfig: nil, - PoolSize: 10 * runtime.GOMAXPROCS(0), - Addrs: []string{}, - MasterName: "", - ClientName: "", - SentinelUsername: "", - SentinelPassword: "", + Host: "127.0.0.1", + Port: 6379, + Username: "", + Password: "", + URL: "", + Database: 0, + Reset: false, + TLSConfig: nil, + PoolSize: 10 * runtime.GOMAXPROCS(0), + Addrs: []string{}, + MasterName: "", + ClientName: "", + SentinelUsername: "", + SentinelPassword: "", } // Helper function to set default values diff --git a/redis/redis_test.go b/redis/redis_test.go index 1ccc2ef5..51d3f0fd 100644 --- a/redis/redis_test.go +++ b/redis/redis_test.go @@ -195,7 +195,7 @@ func Test_Redis_Initalize_WithURL_TLS(t *testing.T) { func Test_Redis_Universal_Addrs(t *testing.T) { // This should failover and create a Single Node connection. testStoreUniversal := New(Config{ - Addrs: []string{"localhost:6379"}, + Addrs: []string{"localhost:6379"}, }) var ( @@ -220,8 +220,8 @@ func Test_Redis_Universal_With_URL_Undefined(t *testing.T) { // This should failover to creating a regular *redis.Client // The URL should get ignored since it's empty testStoreUniversal := New(Config{ - URL: "", - Addrs: []string{"localhost:6379"}, + URL: "", + Addrs: []string{"localhost:6379"}, }) var ( @@ -246,8 +246,8 @@ func Test_Redis_Universal_With_URL_Defined(t *testing.T) { // This should failover to creating a regular *redis.Client // The Addrs field should get ignored since URL is defined testStoreUniversal := New(Config{ - URL: "redis://localhost:6379", - Addrs: []string{"localhost:6355"}, + URL: "redis://localhost:6379", + Addrs: []string{"localhost:6355"}, }) var ( @@ -272,9 +272,9 @@ func Test_Redis_Universal_With_HostPort(t *testing.T) { // This should failover to creating a regular *redis.Client // The Host and Port should get ignored since Addrs is defined testStoreUniversal := New(Config{ - Host: "localhost", - Port: 6388, - Addrs: []string{"localhost:6379"}, + Host: "localhost", + Port: 6388, + Addrs: []string{"localhost:6379"}, }) var ( @@ -299,10 +299,10 @@ func Test_Redis_Universal_With_HostPort_And_URL(t *testing.T) { // This should failover to creating a regular *redis.Client // The Host and Port should get ignored since Addrs is defined testStoreUniversal := New(Config{ - URL: "redis://localhost:6379", - Host: "localhost", - Port: 6388, - Addrs: []string{"localhost:6399"}, + URL: "redis://localhost:6379", + Host: "localhost", + Port: 6388, + Addrs: []string{"localhost:6399"}, }) var ( From ec921b81baed16b4ad0fae9397df04c71279bf21 Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com> Date: Mon, 10 Apr 2023 09:01:10 -0400 Subject: [PATCH 08/11] Add missing v2 --- redis/README.md | 4 ++-- redis/go.mod | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/redis/README.md b/redis/README.md index dbb1a058..5de46b83 100644 --- a/redis/README.md +++ b/redis/README.md @@ -26,13 +26,13 @@ go mod init github.com// ``` And then install the redis implementation: ```bash -go get github.com/gofiber/storage/redis +go get github.com/gofiber/storage/redis/v2 ``` ### Examples Import the storage package. ```go -import "github.com/gofiber/storage/redis" +import "github.com/gofiber/storage/redis/v2" ``` You can use the following possibilities to create a storage: diff --git a/redis/go.mod b/redis/go.mod index 93711026..c1d0c176 100644 --- a/redis/go.mod +++ b/redis/go.mod @@ -1,4 +1,4 @@ -module github.com/gofiber/storage/redis +module github.com/gofiber/storage/redis/v2 go 1.18 From 6014de4ee78caa58b839013f89b201b910dbde83 Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com> Date: Mon, 10 Apr 2023 19:49:47 -0400 Subject: [PATCH 09/11] Add support for testing Redis Cluster --- .github/workflows/test-redis.yml | 6 ++++++ redis/redis_test.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/.github/workflows/test-redis.yml b/.github/workflows/test-redis.yml index 44e4f9ea..6e921669 100644 --- a/.github/workflows/test-redis.yml +++ b/.github/workflows/test-redis.yml @@ -40,6 +40,12 @@ jobs: --tls-key-file ./redis/tests/tls/redis.key \ --tls-ca-cert-file ./redis/tests/tls/ca.crt& + - name: Install Redis Cluster + uses: pfapi/redis-cluster-service@v1 + + - name: Start redis cluster + run: systemctl start redis-cluster + - name: Install Go uses: actions/setup-go@v4 with: diff --git a/redis/redis_test.go b/redis/redis_test.go index 51d3f0fd..883de496 100644 --- a/redis/redis_test.go +++ b/redis/redis_test.go @@ -322,3 +322,33 @@ func Test_Redis_Universal_With_HostPort_And_URL(t *testing.T) { utils.AssertEqual(t, nil, testStoreUniversal.Close()) } + +func Test_Redis_Cluster(t *testing.T) { + testStoreUniversal := New(Config{ + Addrs: []string{ + "localhost:7000", + "localhost:7001", + "localhost:7002", + "localhost:7003", + "localhost:7004", + "localhost:7005", + }, + }) + + var ( + key = "bruce" + val = []byte("wayne") + ) + + err := testStoreUniversal.Set(key, val, 0) + utils.AssertEqual(t, nil, err) + + result, err := testStoreUniversal.Get(key) + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, val, result) + + err = testStoreUniversal.Delete(key) + utils.AssertEqual(t, nil, err) + + utils.AssertEqual(t, nil, testStoreUniversal.Close()) +} \ No newline at end of file From 7769513ca540c4ccf405c01e85f82b5655517acb Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com> Date: Mon, 10 Apr 2023 19:58:31 -0400 Subject: [PATCH 10/11] Update Action used for Redis Cluster --- .github/workflows/test-redis.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test-redis.yml b/.github/workflows/test-redis.yml index 6e921669..7de3e9a3 100644 --- a/.github/workflows/test-redis.yml +++ b/.github/workflows/test-redis.yml @@ -40,11 +40,15 @@ jobs: --tls-key-file ./redis/tests/tls/redis.key \ --tls-ca-cert-file ./redis/tests/tls/ca.crt& - - name: Install Redis Cluster - uses: pfapi/redis-cluster-service@v1 - - - name: Start redis cluster - run: systemctl start redis-cluster + - name: Setup Redis Cluster + uses: vishnudxb/redis-cluster@1 + with: + master1-port: 7000 + master2-port: 7001 + master3-port: 7002 + slave1-port: 7003 + slave2-port: 7004 + slave3-port: 7005 - name: Install Go uses: actions/setup-go@v4 From dff02a29985ad0be6ae133bd944809acdc76c254 Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com> Date: Mon, 10 Apr 2023 20:01:15 -0400 Subject: [PATCH 11/11] Fix action version number --- .github/workflows/test-redis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-redis.yml b/.github/workflows/test-redis.yml index 7de3e9a3..01ffa35d 100644 --- a/.github/workflows/test-redis.yml +++ b/.github/workflows/test-redis.yml @@ -41,7 +41,7 @@ jobs: --tls-ca-cert-file ./redis/tests/tls/ca.crt& - name: Setup Redis Cluster - uses: vishnudxb/redis-cluster@1 + uses: vishnudxb/redis-cluster@1.0.5 with: master1-port: 7000 master2-port: 7001