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()) }