github.com/craicoverflow/tyk@v2.9.6-rc3+incompatible/storage/redis_cluster.go (about)

     1  package storage
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strconv"
     7  	"strings"
     8  	"sync"
     9  	"time"
    10  
    11  	"crypto/tls"
    12  
    13  	"github.com/go-redis/redis"
    14  	uuid "github.com/satori/go.uuid"
    15  	"github.com/sirupsen/logrus"
    16  
    17  	"github.com/TykTechnologies/tyk/config"
    18  )
    19  
    20  // ------------------- REDIS CLUSTER STORAGE MANAGER -------------------------------
    21  
    22  const (
    23  	waitStorageRetriesNum      = 5
    24  	waitStorageRetriesInterval = 1 * time.Second
    25  
    26  	defaultRedisPort = 6379
    27  )
    28  
    29  var (
    30  	redisSingletonMu sync.RWMutex
    31  
    32  	redisClusterSingleton      redis.UniversalClient
    33  	redisCacheClusterSingleton redis.UniversalClient
    34  )
    35  
    36  // RedisCluster is a storage manager that uses the redis database.
    37  type RedisCluster struct {
    38  	KeyPrefix string
    39  	HashKeys  bool
    40  	IsCache   bool
    41  }
    42  
    43  func clusterConnectionIsOpen(cluster *RedisCluster) bool {
    44  	testKey := "redis-test-" + uuid.NewV4().String()
    45  	// set test key
    46  	if err := cluster.SetKey(testKey, "test", 1); err != nil {
    47  		return false
    48  	}
    49  	// get test key
    50  	if _, err := cluster.GetKey(testKey); err != nil {
    51  		return false
    52  	}
    53  	return true
    54  }
    55  
    56  // IsConnected waits with retries until Redis connection pools are connected
    57  func IsConnected() bool {
    58  	// create temporary ones to access singletons
    59  	testClusters := []*RedisCluster{
    60  		{},
    61  	}
    62  	if config.Global().EnableSeperateCacheStore {
    63  		testClusters = append(testClusters, &RedisCluster{IsCache: true})
    64  	}
    65  	for _, cluster := range testClusters {
    66  		cluster.Connect()
    67  	}
    68  
    69  	// wait for connection pools with retries
    70  	retryNum := 0
    71  	for {
    72  		if retryNum == waitStorageRetriesNum {
    73  			log.Error("Waiting for Redis connection pools failed")
    74  			return false
    75  		}
    76  
    77  		// check that redis is available
    78  		var redisIsReady bool
    79  		for _, cluster := range testClusters {
    80  			redisIsReady = cluster.singleton() != nil && clusterConnectionIsOpen(cluster)
    81  			if !redisIsReady {
    82  				break
    83  			}
    84  		}
    85  		if redisIsReady {
    86  			break
    87  		}
    88  
    89  		// sleep before next check
    90  		log.WithField("currRetry", retryNum).Info("Waiting for Redis connection pools to be ready")
    91  		time.Sleep(waitStorageRetriesInterval)
    92  		retryNum++
    93  	}
    94  	log.WithField("currRetry", retryNum).Info("Redis connection pools are ready after number of retires")
    95  
    96  	return true
    97  }
    98  
    99  func NewRedisClusterPool(isCache bool) redis.UniversalClient {
   100  	// redisSingletonMu is locked and we know the singleton is nil
   101  	cfg := config.Global().Storage
   102  	if isCache && config.Global().EnableSeperateCacheStore {
   103  		cfg = config.Global().CacheStorage
   104  	}
   105  
   106  	log.Debug("Creating new Redis connection pool")
   107  
   108  	// poolSize applies per cluster node and not for the whole cluster.
   109  	poolSize := 500
   110  	if cfg.MaxActive > 0 {
   111  		poolSize = cfg.MaxActive
   112  	}
   113  
   114  	timeout := 5 * time.Second
   115  
   116  	if cfg.Timeout > 0 {
   117  		timeout = time.Duration(cfg.Timeout) * time.Second
   118  	}
   119  
   120  	var tlsConfig *tls.Config
   121  
   122  	if cfg.UseSSL {
   123  		tlsConfig = &tls.Config{
   124  			InsecureSkipVerify: cfg.SSLInsecureSkipVerify,
   125  		}
   126  	}
   127  
   128  	var client redis.UniversalClient
   129  	opts := &RedisOpts{
   130  		Addrs:        getRedisAddrs(cfg),
   131  		MasterName:   cfg.MasterName,
   132  		Password:     cfg.Password,
   133  		DB:           cfg.Database,
   134  		DialTimeout:  timeout,
   135  		ReadTimeout:  timeout,
   136  		WriteTimeout: timeout,
   137  		IdleTimeout:  240 * timeout,
   138  		PoolSize:     poolSize,
   139  		TLSConfig:    tlsConfig,
   140  	}
   141  
   142  	if opts.MasterName != "" {
   143  		log.Info("--> [REDIS] Creating sentinel-backed failover client")
   144  		client = redis.NewFailoverClient(opts.failover())
   145  	} else if cfg.EnableCluster {
   146  		log.Info("--> [REDIS] Creating cluster client")
   147  		client = redis.NewClusterClient(opts.cluster())
   148  	} else {
   149  		log.Info("--> [REDIS] Creating single-node client")
   150  		client = redis.NewClient(opts.simple())
   151  	}
   152  
   153  	return client
   154  }
   155  
   156  func getRedisAddrs(config config.StorageOptionsConf) (addrs []string) {
   157  	if len(config.Addrs) != 0 {
   158  		addrs = config.Addrs
   159  	} else {
   160  		for h, p := range config.Hosts {
   161  			addr := h + ":" + p
   162  			addrs = append(addrs, addr)
   163  		}
   164  	}
   165  
   166  	if len(addrs) == 0 && config.Port != 0 {
   167  		addr := config.Host + ":" + strconv.Itoa(config.Port)
   168  		addrs = append(addrs, addr)
   169  	}
   170  
   171  	return addrs
   172  }
   173  
   174  // RedisOpts is the overriden type of redis.UniversalOptions. simple() and cluster() functions are not public
   175  // in redis library. Therefore, they are redefined in here to use in creation of new redis cluster logic.
   176  // We don't want to use redis.NewUniversalClient() logic.
   177  type RedisOpts redis.UniversalOptions
   178  
   179  func (o *RedisOpts) cluster() *redis.ClusterOptions {
   180  	if len(o.Addrs) == 0 {
   181  		o.Addrs = []string{"127.0.0.1:6379"}
   182  	}
   183  
   184  	return &redis.ClusterOptions{
   185  		Addrs:     o.Addrs,
   186  		OnConnect: o.OnConnect,
   187  
   188  		Password: o.Password,
   189  
   190  		MaxRedirects:   o.MaxRedirects,
   191  		ReadOnly:       o.ReadOnly,
   192  		RouteByLatency: o.RouteByLatency,
   193  		RouteRandomly:  o.RouteRandomly,
   194  
   195  		MaxRetries:      o.MaxRetries,
   196  		MinRetryBackoff: o.MinRetryBackoff,
   197  		MaxRetryBackoff: o.MaxRetryBackoff,
   198  
   199  		DialTimeout:        o.DialTimeout,
   200  		ReadTimeout:        o.ReadTimeout,
   201  		WriteTimeout:       o.WriteTimeout,
   202  		PoolSize:           o.PoolSize,
   203  		MinIdleConns:       o.MinIdleConns,
   204  		MaxConnAge:         o.MaxConnAge,
   205  		PoolTimeout:        o.PoolTimeout,
   206  		IdleTimeout:        o.IdleTimeout,
   207  		IdleCheckFrequency: o.IdleCheckFrequency,
   208  
   209  		TLSConfig: o.TLSConfig,
   210  	}
   211  }
   212  
   213  func (o *RedisOpts) simple() *redis.Options {
   214  	addr := "127.0.0.1:6379"
   215  	if len(o.Addrs) > 0 {
   216  		addr = o.Addrs[0]
   217  	}
   218  
   219  	return &redis.Options{
   220  		Addr:      addr,
   221  		OnConnect: o.OnConnect,
   222  
   223  		DB:       o.DB,
   224  		Password: o.Password,
   225  
   226  		MaxRetries:      o.MaxRetries,
   227  		MinRetryBackoff: o.MinRetryBackoff,
   228  		MaxRetryBackoff: o.MaxRetryBackoff,
   229  
   230  		DialTimeout:  o.DialTimeout,
   231  		ReadTimeout:  o.ReadTimeout,
   232  		WriteTimeout: o.WriteTimeout,
   233  
   234  		PoolSize:           o.PoolSize,
   235  		MinIdleConns:       o.MinIdleConns,
   236  		MaxConnAge:         o.MaxConnAge,
   237  		PoolTimeout:        o.PoolTimeout,
   238  		IdleTimeout:        o.IdleTimeout,
   239  		IdleCheckFrequency: o.IdleCheckFrequency,
   240  
   241  		TLSConfig: o.TLSConfig,
   242  	}
   243  }
   244  
   245  func (o *RedisOpts) failover() *redis.FailoverOptions {
   246  	if len(o.Addrs) == 0 {
   247  		o.Addrs = []string{"127.0.0.1:26379"}
   248  	}
   249  
   250  	return &redis.FailoverOptions{
   251  		SentinelAddrs: o.Addrs,
   252  		MasterName:    o.MasterName,
   253  		OnConnect:     o.OnConnect,
   254  
   255  		DB:       o.DB,
   256  		Password: o.Password,
   257  
   258  		MaxRetries:      o.MaxRetries,
   259  		MinRetryBackoff: o.MinRetryBackoff,
   260  		MaxRetryBackoff: o.MaxRetryBackoff,
   261  
   262  		DialTimeout:  o.DialTimeout,
   263  		ReadTimeout:  o.ReadTimeout,
   264  		WriteTimeout: o.WriteTimeout,
   265  
   266  		PoolSize:           o.PoolSize,
   267  		MinIdleConns:       o.MinIdleConns,
   268  		MaxConnAge:         o.MaxConnAge,
   269  		PoolTimeout:        o.PoolTimeout,
   270  		IdleTimeout:        o.IdleTimeout,
   271  		IdleCheckFrequency: o.IdleCheckFrequency,
   272  
   273  		TLSConfig: o.TLSConfig,
   274  	}
   275  }
   276  
   277  // Connect will establish a connection to the r.singleton()
   278  func (r *RedisCluster) Connect() bool {
   279  	redisSingletonMu.Lock()
   280  	defer redisSingletonMu.Unlock()
   281  
   282  	disconnected := redisClusterSingleton == nil
   283  	if r.IsCache {
   284  		disconnected = redisCacheClusterSingleton == nil
   285  	}
   286  
   287  	if disconnected {
   288  		log.Debug("Connecting to redis cluster")
   289  		if r.IsCache {
   290  			redisCacheClusterSingleton = NewRedisClusterPool(true)
   291  			return true
   292  		}
   293  		redisClusterSingleton = NewRedisClusterPool(false)
   294  		return true
   295  	}
   296  
   297  	log.Debug("Storage Engine already initialised...")
   298  	return true
   299  }
   300  
   301  func (r *RedisCluster) singleton() redis.UniversalClient {
   302  	redisSingletonMu.RLock()
   303  	defer redisSingletonMu.RUnlock()
   304  
   305  	if r.IsCache {
   306  		return redisCacheClusterSingleton
   307  	}
   308  	return redisClusterSingleton
   309  }
   310  
   311  func (r *RedisCluster) hashKey(in string) string {
   312  	if !r.HashKeys {
   313  		// Not hashing? Return the raw key
   314  		return in
   315  	}
   316  	return HashStr(in)
   317  }
   318  
   319  func (r *RedisCluster) fixKey(keyName string) string {
   320  	return r.KeyPrefix + r.hashKey(keyName)
   321  }
   322  
   323  func (r *RedisCluster) cleanKey(keyName string) string {
   324  	return strings.Replace(keyName, r.KeyPrefix, "", 1)
   325  }
   326  
   327  func (r *RedisCluster) ensureConnection() {
   328  	if r.singleton() != nil {
   329  		// already connected
   330  		return
   331  	}
   332  	log.Info("Connection dropped, reconnecting...")
   333  	for {
   334  		r.Connect()
   335  		if r.singleton() != nil {
   336  			// reconnection worked
   337  			return
   338  		}
   339  		log.Info("Reconnecting again...")
   340  	}
   341  }
   342  
   343  // GetKey will retrieve a key from the database
   344  func (r *RedisCluster) GetKey(keyName string) (string, error) {
   345  	r.ensureConnection()
   346  
   347  	cluster := r.singleton()
   348  
   349  	value, err := cluster.Get(r.fixKey(keyName)).Result()
   350  	if err != nil {
   351  		log.Debug("Error trying to get value:", err)
   352  		return "", ErrKeyNotFound
   353  	}
   354  
   355  	return value, nil
   356  }
   357  
   358  // GetMultiKey gets multiple keys from the database
   359  func (r *RedisCluster) GetMultiKey(keys []string) ([]string, error) {
   360  	r.ensureConnection()
   361  	cluster := r.singleton()
   362  	keyNames := make([]string, len(keys))
   363  	copy(keyNames, keys)
   364  	for index, val := range keyNames {
   365  		keyNames[index] = r.fixKey(val)
   366  	}
   367  
   368  	result := make([]string, 0)
   369  
   370  	switch v := cluster.(type) {
   371  	case *redis.ClusterClient:
   372  		{
   373  			getCmds := make([]*redis.StringCmd, 0)
   374  			pipe := v.Pipeline()
   375  			for _, key := range keyNames {
   376  				getCmds = append(getCmds, pipe.Get(key))
   377  			}
   378  			_, err := pipe.Exec()
   379  			if err != nil && err != redis.Nil {
   380  				log.WithError(err).Debug("Error trying to get value")
   381  				return nil, ErrKeyNotFound
   382  			}
   383  			for _, cmd := range getCmds {
   384  				result = append(result, cmd.Val())
   385  			}
   386  		}
   387  	case *redis.Client:
   388  		{
   389  			values, err := cluster.MGet(keyNames...).Result()
   390  			if err != nil {
   391  				log.WithError(err).Debug("Error trying to get value")
   392  				return nil, ErrKeyNotFound
   393  			}
   394  			for _, val := range values {
   395  				strVal := fmt.Sprint(val)
   396  				if strVal == "<nil>" {
   397  					strVal = ""
   398  				}
   399  				result = append(result, strVal)
   400  			}
   401  		}
   402  	}
   403  
   404  	for _, val := range result {
   405  		if val != "" {
   406  			return result, nil
   407  		}
   408  	}
   409  
   410  	return nil, ErrKeyNotFound
   411  }
   412  
   413  func (r *RedisCluster) GetKeyTTL(keyName string) (ttl int64, err error) {
   414  	r.ensureConnection()
   415  	duration, err := r.singleton().TTL(r.fixKey(keyName)).Result()
   416  	return int64(duration.Seconds()), err
   417  }
   418  
   419  func (r *RedisCluster) GetRawKey(keyName string) (string, error) {
   420  	r.ensureConnection()
   421  	value, err := r.singleton().Get(keyName).Result()
   422  	if err != nil {
   423  		log.Debug("Error trying to get value:", err)
   424  		return "", ErrKeyNotFound
   425  	}
   426  
   427  	return value, nil
   428  }
   429  
   430  func (r *RedisCluster) GetExp(keyName string) (int64, error) {
   431  	//	log.Debug("Getting exp for key: ", r.fixKey(keyName))
   432  	r.ensureConnection()
   433  
   434  	value, err := r.singleton().TTL(r.fixKey(keyName)).Result()
   435  	if err != nil {
   436  		log.Error("Error trying to get TTL: ", err)
   437  		return 0, ErrKeyNotFound
   438  	}
   439  	return int64(value.Seconds()), nil
   440  }
   441  
   442  func (r *RedisCluster) SetExp(keyName string, timeout int64) error {
   443  	err := r.singleton().Expire(r.fixKey(keyName), time.Duration(timeout)*time.Second).Err()
   444  	if err != nil {
   445  		log.Error("Could not EXPIRE key: ", err)
   446  	}
   447  	return err
   448  }
   449  
   450  // SetKey will create (or update) a key value in the store
   451  func (r *RedisCluster) SetKey(keyName, session string, timeout int64) error {
   452  	//log.Debug("[STORE] SET Raw key is: ", keyName)
   453  	//log.Debug("[STORE] Setting key: ", r.fixKey(keyName))
   454  
   455  	r.ensureConnection()
   456  	err := r.singleton().Set(r.fixKey(keyName), session, 0).Err()
   457  	if err != nil {
   458  		log.Error("Error trying to set value: ", err)
   459  		return err
   460  	}
   461  
   462  	if timeout > 0 {
   463  		err := r.singleton().Expire(r.fixKey(keyName), time.Duration(timeout)*time.Second).Err()
   464  		if err != nil {
   465  			log.Error("Error trying to set expiry:", err)
   466  			return err
   467  		}
   468  	}
   469  
   470  	return nil
   471  }
   472  
   473  func (r *RedisCluster) SetRawKey(keyName, session string, timeout int64) error {
   474  	r.ensureConnection()
   475  	err := r.singleton().Set(keyName, session, time.Duration(timeout)*time.Second).Err()
   476  	if err != nil {
   477  		log.Error("Error trying to set value: ", err)
   478  		return err
   479  	}
   480  	return nil
   481  }
   482  
   483  // Decrement will decrement a key in redis
   484  func (r *RedisCluster) Decrement(keyName string) {
   485  	keyName = r.fixKey(keyName)
   486  	// log.Debug("Decrementing key: ", keyName)
   487  	r.ensureConnection()
   488  	err := r.singleton().Decr(keyName).Err()
   489  	if err != nil {
   490  		log.Error("Error trying to decrement value:", err)
   491  	}
   492  }
   493  
   494  // IncrementWithExpire will increment a key in redis
   495  func (r *RedisCluster) IncrememntWithExpire(keyName string, expire int64) int64 {
   496  	// log.Debug("Incrementing raw key: ", keyName)
   497  	r.ensureConnection()
   498  
   499  	// This function uses a raw key, so we shouldn't call fixKey
   500  	fixedKey := keyName
   501  	val, err := r.singleton().Incr(fixedKey).Result()
   502  
   503  	if err != nil {
   504  		log.Error("Error trying to increment value:", err)
   505  	} else {
   506  		log.Debug("Incremented key: ", fixedKey, ", val is: ", val)
   507  	}
   508  
   509  	if val == 1 && expire != 0 {
   510  		log.Debug("--> Setting Expire")
   511  		r.singleton().Expire(fixedKey, time.Duration(expire)*time.Second)
   512  	}
   513  
   514  	return val
   515  }
   516  
   517  // GetKeys will return all keys according to the filter (filter is a prefix - e.g. tyk.keys.*)
   518  func (r *RedisCluster) GetKeys(filter string) []string {
   519  	r.ensureConnection()
   520  	client := r.singleton()
   521  
   522  	filterHash := ""
   523  	if filter != "" {
   524  		filterHash = r.hashKey(filter)
   525  	}
   526  	searchStr := r.KeyPrefix + filterHash + "*"
   527  	log.Debug("[STORE] Getting list by: ", searchStr)
   528  
   529  	fnFetchKeys := func(client *redis.Client) ([]string, error) {
   530  		values := make([]string, 0)
   531  
   532  		iter := client.Scan(0, searchStr, 0).Iterator()
   533  		for iter.Next() {
   534  			values = append(values, iter.Val())
   535  		}
   536  
   537  		if err := iter.Err(); err != nil {
   538  			return nil, err
   539  		}
   540  
   541  		return values, nil
   542  	}
   543  
   544  	var err error
   545  	sessions := make([]string, 0)
   546  
   547  	switch v := client.(type) {
   548  	case *redis.ClusterClient:
   549  		ch := make(chan []string)
   550  
   551  		go func() {
   552  			err = v.ForEachMaster(func(client *redis.Client) error {
   553  				values, err := fnFetchKeys(client)
   554  				if err != nil {
   555  					return err
   556  				}
   557  
   558  				ch <- values
   559  				return nil
   560  			})
   561  			close(ch)
   562  		}()
   563  
   564  		for res := range ch {
   565  			sessions = append(sessions, res...)
   566  		}
   567  	case *redis.Client:
   568  		sessions, err = fnFetchKeys(v)
   569  	}
   570  
   571  	if err != nil {
   572  		log.Error("Error while fetching keys:", err)
   573  		return nil
   574  	}
   575  
   576  	for i, v := range sessions {
   577  		sessions[i] = r.cleanKey(v)
   578  	}
   579  
   580  	return sessions
   581  }
   582  
   583  // GetKeysAndValuesWithFilter will return all keys and their values with a filter
   584  func (r *RedisCluster) GetKeysAndValuesWithFilter(filter string) map[string]string {
   585  	r.ensureConnection()
   586  	keys := r.GetKeys(filter)
   587  	if keys == nil {
   588  		log.Error("Error trying to get filtered client keys")
   589  		return nil
   590  	}
   591  
   592  	if len(keys) == 0 {
   593  		return nil
   594  	}
   595  
   596  	for i, v := range keys {
   597  		keys[i] = r.KeyPrefix + v
   598  	}
   599  
   600  	client := r.singleton()
   601  	values := make([]string, 0)
   602  
   603  	switch v := client.(type) {
   604  	case *redis.ClusterClient:
   605  		{
   606  			getCmds := make([]*redis.StringCmd, 0)
   607  			pipe := v.Pipeline()
   608  			for _, key := range keys {
   609  				getCmds = append(getCmds, pipe.Get(key))
   610  			}
   611  			_, err := pipe.Exec()
   612  			if err != nil && err != redis.Nil {
   613  				log.Error("Error trying to get client keys: ", err)
   614  				return nil
   615  			}
   616  
   617  			for _, cmd := range getCmds {
   618  				values = append(values, cmd.Val())
   619  			}
   620  		}
   621  	case *redis.Client:
   622  		{
   623  			result, err := v.MGet(keys...).Result()
   624  			if err != nil {
   625  				log.Error("Error trying to get client keys: ", err)
   626  				return nil
   627  			}
   628  
   629  			for _, val := range result {
   630  				strVal := fmt.Sprint(val)
   631  				if strVal == "<nil>" {
   632  					strVal = ""
   633  				}
   634  				values = append(values, strVal)
   635  			}
   636  		}
   637  	}
   638  
   639  	m := make(map[string]string)
   640  	for i, v := range keys {
   641  		m[r.cleanKey(v)] = values[i]
   642  
   643  	}
   644  
   645  	return m
   646  }
   647  
   648  // GetKeysAndValues will return all keys and their values - not to be used lightly
   649  func (r *RedisCluster) GetKeysAndValues() map[string]string {
   650  	return r.GetKeysAndValuesWithFilter("")
   651  }
   652  
   653  // DeleteKey will remove a key from the database
   654  func (r *RedisCluster) DeleteKey(keyName string) bool {
   655  	r.ensureConnection()
   656  	log.Debug("DEL Key was: ", keyName)
   657  	log.Debug("DEL Key became: ", r.fixKey(keyName))
   658  	n, err := r.singleton().Del(r.fixKey(keyName)).Result()
   659  	if err != nil {
   660  		log.WithError(err).Error("Error trying to delete key")
   661  	}
   662  
   663  	return n > 0
   664  }
   665  
   666  // DeleteAllKeys will remove all keys from the database.
   667  func (r *RedisCluster) DeleteAllKeys() bool {
   668  	r.ensureConnection()
   669  	n, err := r.singleton().FlushAll().Result()
   670  	if err != nil {
   671  		log.WithError(err).Error("Error trying to delete keys")
   672  	}
   673  
   674  	if n == "OK" {
   675  		return true
   676  	}
   677  
   678  	return false
   679  }
   680  
   681  // DeleteKey will remove a key from the database without prefixing, assumes user knows what they are doing
   682  func (r *RedisCluster) DeleteRawKey(keyName string) bool {
   683  	r.ensureConnection()
   684  	n, err := r.singleton().Del(keyName).Result()
   685  	if err != nil {
   686  		log.WithError(err).Error("Error trying to delete key")
   687  	}
   688  
   689  	return n > 0
   690  }
   691  
   692  // DeleteKeys will remove a group of keys in bulk
   693  func (r *RedisCluster) DeleteScanMatch(pattern string) bool {
   694  	r.ensureConnection()
   695  	client := r.singleton()
   696  	log.Debug("Deleting: ", pattern)
   697  
   698  	fnScan := func(client *redis.Client) ([]string, error) {
   699  		values := make([]string, 0)
   700  
   701  		iter := client.Scan(0, pattern, 0).Iterator()
   702  		for iter.Next() {
   703  			values = append(values, iter.Val())
   704  		}
   705  
   706  		if err := iter.Err(); err != nil {
   707  			return nil, err
   708  		}
   709  
   710  		return values, nil
   711  	}
   712  
   713  	var err error
   714  	var keys []string
   715  
   716  	switch v := client.(type) {
   717  	case *redis.ClusterClient:
   718  		ch := make(chan []string)
   719  		go func() {
   720  			err = v.ForEachMaster(func(client *redis.Client) error {
   721  				values, err := fnScan(client)
   722  				if err != nil {
   723  					return err
   724  				}
   725  
   726  				ch <- values
   727  				return nil
   728  			})
   729  			close(ch)
   730  		}()
   731  
   732  		for vals := range ch {
   733  			keys = append(keys, vals...)
   734  		}
   735  	case *redis.Client:
   736  		keys, err = fnScan(v)
   737  	}
   738  
   739  	if err != nil {
   740  		log.Error("SCAN command field with err:", err)
   741  		return false
   742  	}
   743  
   744  	if len(keys) > 0 {
   745  		for _, name := range keys {
   746  			log.Info("Deleting: ", name)
   747  			err := client.Del(name).Err()
   748  			if err != nil {
   749  				log.Error("Error trying to delete key: ", name, " - ", err)
   750  			}
   751  		}
   752  		log.Info("Deleted: ", len(keys), " records")
   753  	} else {
   754  		log.Debug("RedisCluster called DEL - Nothing to delete")
   755  	}
   756  
   757  	return true
   758  }
   759  
   760  // DeleteKeys will remove a group of keys in bulk
   761  func (r *RedisCluster) DeleteKeys(keys []string) bool {
   762  	r.ensureConnection()
   763  	if len(keys) > 0 {
   764  		for i, v := range keys {
   765  			keys[i] = r.fixKey(v)
   766  		}
   767  
   768  		log.Debug("Deleting: ", keys)
   769  		client := r.singleton()
   770  		switch v := client.(type) {
   771  		case *redis.ClusterClient:
   772  			{
   773  				pipe := v.Pipeline()
   774  				for _, k := range keys {
   775  					pipe.Del(k)
   776  				}
   777  
   778  				if _, err := pipe.Exec(); err != nil {
   779  					log.Error("Error trying to delete keys:", err)
   780  				}
   781  			}
   782  		case *redis.Client:
   783  			{
   784  				_, err := v.Del(keys...).Result()
   785  				if err != nil {
   786  					log.Error("Error trying to delete keys: ", err)
   787  				}
   788  			}
   789  		}
   790  	} else {
   791  		log.Debug("RedisCluster called DEL - Nothing to delete")
   792  	}
   793  
   794  	return true
   795  }
   796  
   797  // StartPubSubHandler will listen for a signal and run the callback for
   798  // every subscription and message event.
   799  func (r *RedisCluster) StartPubSubHandler(channel string, callback func(interface{})) error {
   800  	r.ensureConnection()
   801  	client := r.singleton()
   802  	if client == nil {
   803  		return errors.New("Redis connection failed")
   804  	}
   805  
   806  	pubsub := client.Subscribe(channel)
   807  	defer pubsub.Close()
   808  
   809  	for {
   810  		msg, err := pubsub.Receive()
   811  		if err != nil {
   812  			log.Error("Error while receiving pubsub message:", err)
   813  			return err
   814  		}
   815  		switch v := msg.(type) {
   816  		case *redis.Message:
   817  			callback(v)
   818  
   819  		case *redis.Subscription:
   820  			callback(v)
   821  
   822  		case error:
   823  			log.Error("Redis disconnected or error received, attempting to reconnect: ", v)
   824  			return v
   825  		}
   826  	}
   827  }
   828  
   829  func (r *RedisCluster) Publish(channel, message string) error {
   830  	r.ensureConnection()
   831  	err := r.singleton().Publish(channel, message).Err()
   832  	if err != nil {
   833  		log.Error("Error trying to set value: ", err)
   834  		return err
   835  	}
   836  	return nil
   837  }
   838  
   839  func (r *RedisCluster) GetAndDeleteSet(keyName string) []interface{} {
   840  	log.Debug("Getting raw key set: ", keyName)
   841  	r.ensureConnection()
   842  	log.Debug("keyName is: ", keyName)
   843  	fixedKey := r.fixKey(keyName)
   844  	log.Debug("Fixed keyname is: ", fixedKey)
   845  
   846  	client := r.singleton()
   847  
   848  	var lrange *redis.StringSliceCmd
   849  	_, err := client.TxPipelined(func(pipe redis.Pipeliner) error {
   850  		lrange = pipe.LRange(fixedKey, 0, -1)
   851  		pipe.Del(fixedKey)
   852  		return nil
   853  	})
   854  	if err != nil {
   855  		log.Error("Multi command failed: ", err)
   856  		return nil
   857  	}
   858  
   859  	vals := lrange.Val()
   860  	log.Debug("Analytics returned: ", len(vals))
   861  	if len(vals) == 0 {
   862  		return nil
   863  	}
   864  
   865  	log.Debug("Unpacked vals: ", len(vals))
   866  	result := make([]interface{}, len(vals))
   867  	for i, v := range vals {
   868  		result[i] = v
   869  	}
   870  
   871  	return result
   872  }
   873  
   874  func (r *RedisCluster) AppendToSet(keyName, value string) {
   875  	fixedKey := r.fixKey(keyName)
   876  	log.WithField("keyName", keyName).Debug("Pushing to raw key list")
   877  	log.WithField("fixedKey", fixedKey).Debug("Appending to fixed key list")
   878  
   879  	r.ensureConnection()
   880  	if err := r.singleton().RPush(fixedKey, value).Err(); err != nil {
   881  		log.WithError(err).Error("Error trying to append to set keys")
   882  	}
   883  }
   884  
   885  //Exists check if keyName exists
   886  func (r *RedisCluster) Exists(keyName string) (bool, error) {
   887  	fixedKey := r.fixKey(keyName)
   888  	log.WithField("keyName", fixedKey).Debug("Checking if exists")
   889  
   890  	exists, err := r.singleton().Exists(fixedKey).Result()
   891  	if err != nil {
   892  		log.Error("Error trying to check if key exists: ", err)
   893  		return false, err
   894  	}
   895  	if exists == 1 {
   896  		return true, nil
   897  	}
   898  	return false, nil
   899  }
   900  
   901  // RemoveFromList delete an value from a list idetinfied with the keyName
   902  func (r *RedisCluster) RemoveFromList(keyName, value string) error {
   903  	fixedKey := r.fixKey(keyName)
   904  	logEntry := logrus.Fields{
   905  		"keyName":  keyName,
   906  		"fixedKey": fixedKey,
   907  		"value":    value,
   908  	}
   909  	log.WithFields(logEntry).Debug("Removing value from list")
   910  
   911  	if err := r.singleton().LRem(fixedKey, 0, value).Err(); err != nil {
   912  		log.WithFields(logEntry).WithError(err).Error("LREM command failed")
   913  		return err
   914  	}
   915  
   916  	return nil
   917  }
   918  
   919  // GetListRange gets range of elements of list identified by keyName
   920  func (r *RedisCluster) GetListRange(keyName string, from, to int64) ([]string, error) {
   921  	fixedKey := r.fixKey(keyName)
   922  	logEntry := logrus.Fields{
   923  		"keyName":  keyName,
   924  		"fixedKey": fixedKey,
   925  		"from":     from,
   926  		"to":       to,
   927  	}
   928  	log.WithFields(logEntry).Debug("Getting list range")
   929  
   930  	elements, err := r.singleton().LRange(fixedKey, from, to).Result()
   931  	if err != nil {
   932  		log.WithFields(logEntry).WithError(err).Error("LRANGE command failed")
   933  		return nil, err
   934  	}
   935  
   936  	return elements, nil
   937  }
   938  
   939  func (r *RedisCluster) AppendToSetPipelined(key string, values []string) {
   940  	if len(values) == 0 {
   941  		return
   942  	}
   943  
   944  	fixedKey := r.fixKey(key)
   945  	r.ensureConnection()
   946  	client := r.singleton()
   947  
   948  	pipe := client.Pipeline()
   949  	for _, val := range values {
   950  		pipe.RPush(fixedKey, val)
   951  	}
   952  
   953  	if _, err := pipe.Exec(); err != nil {
   954  		log.WithError(err).Error("Error trying to append to set keys")
   955  	}
   956  }
   957  
   958  func (r *RedisCluster) GetSet(keyName string) (map[string]string, error) {
   959  	log.Debug("Getting from key set: ", keyName)
   960  	log.Debug("Getting from fixed key set: ", r.fixKey(keyName))
   961  	r.ensureConnection()
   962  
   963  	val, err := r.singleton().SMembers(r.fixKey(keyName)).Result()
   964  	if err != nil {
   965  		log.Error("Error trying to get key set:", err)
   966  		return nil, err
   967  	}
   968  
   969  	result := make(map[string]string)
   970  	for i, value := range val {
   971  		result[strconv.Itoa(i)] = value
   972  	}
   973  
   974  	return result, nil
   975  }
   976  
   977  func (r *RedisCluster) AddToSet(keyName, value string) {
   978  	log.Debug("Pushing to raw key set: ", keyName)
   979  	log.Debug("Pushing to fixed key set: ", r.fixKey(keyName))
   980  	r.ensureConnection()
   981  	err := r.singleton().SAdd(r.fixKey(keyName), value).Err()
   982  	if err != nil {
   983  		log.Error("Error trying to append keys: ", err)
   984  	}
   985  }
   986  
   987  func (r *RedisCluster) RemoveFromSet(keyName, value string) {
   988  	log.Debug("Removing from raw key set: ", keyName)
   989  	log.Debug("Removing from fixed key set: ", r.fixKey(keyName))
   990  	r.ensureConnection()
   991  
   992  	err := r.singleton().SRem(r.fixKey(keyName), value).Err()
   993  	if err != nil {
   994  		log.Error("Error trying to remove keys: ", err)
   995  	}
   996  }
   997  
   998  func (r *RedisCluster) IsMemberOfSet(keyName, value string) bool {
   999  	r.ensureConnection()
  1000  	val, err := r.singleton().SIsMember(r.fixKey(keyName), value).Result()
  1001  
  1002  	if err != nil {
  1003  		log.Error("Error trying to check set memeber: ", err)
  1004  		return false
  1005  	}
  1006  
  1007  	log.Debug("SISMEMBER", keyName, value, val, err)
  1008  
  1009  	return val == true
  1010  }
  1011  
  1012  // SetRollingWindow will append to a sorted set in redis and extract a timed window of values
  1013  func (r *RedisCluster) SetRollingWindow(keyName string, per int64, value_override string, pipeline bool) (int, []interface{}) {
  1014  	log.Debug("Incrementing raw key: ", keyName)
  1015  	r.ensureConnection()
  1016  	log.Debug("keyName is: ", keyName)
  1017  	now := time.Now()
  1018  	log.Debug("Now is:", now)
  1019  	onePeriodAgo := now.Add(time.Duration(-1*per) * time.Second)
  1020  	log.Debug("Then is: ", onePeriodAgo)
  1021  
  1022  	client := r.singleton()
  1023  	var zrange *redis.StringSliceCmd
  1024  
  1025  	pipeFn := func(pipe redis.Pipeliner) error {
  1026  		pipe.ZRemRangeByScore(keyName, "-inf", strconv.Itoa(int(onePeriodAgo.UnixNano())))
  1027  		zrange = pipe.ZRange(keyName, 0, -1)
  1028  
  1029  		element := redis.Z{
  1030  			Score: float64(now.UnixNano()),
  1031  		}
  1032  
  1033  		if value_override != "-1" {
  1034  			element.Member = value_override
  1035  		} else {
  1036  			element.Member = strconv.Itoa(int(now.UnixNano()))
  1037  		}
  1038  
  1039  		pipe.ZAdd(keyName, element)
  1040  		pipe.Expire(keyName, time.Duration(per)*time.Second)
  1041  
  1042  		return nil
  1043  	}
  1044  
  1045  	var err error
  1046  	if pipeline {
  1047  		_, err = client.Pipelined(pipeFn)
  1048  	} else {
  1049  		_, err = client.TxPipelined(pipeFn)
  1050  	}
  1051  
  1052  	if err != nil {
  1053  		log.Error("Multi command failed: ", err)
  1054  		return 0, nil
  1055  	}
  1056  
  1057  	values := zrange.Val()
  1058  
  1059  	// Check actual value
  1060  	if values == nil {
  1061  		return 0, nil
  1062  	}
  1063  
  1064  	intVal := len(values)
  1065  	result := make([]interface{}, len(values))
  1066  
  1067  	for i, v := range values {
  1068  		result[i] = v
  1069  	}
  1070  
  1071  	log.Debug("Returned: ", intVal)
  1072  
  1073  	return intVal, result
  1074  }
  1075  
  1076  func (r RedisCluster) GetRollingWindow(keyName string, per int64, pipeline bool) (int, []interface{}) {
  1077  	r.ensureConnection()
  1078  	now := time.Now()
  1079  	onePeriodAgo := now.Add(time.Duration(-1*per) * time.Second)
  1080  
  1081  	client := r.singleton()
  1082  	var zrange *redis.StringSliceCmd
  1083  
  1084  	pipeFn := func(pipe redis.Pipeliner) error {
  1085  		pipe.ZRemRangeByScore(keyName, "-inf", strconv.Itoa(int(onePeriodAgo.UnixNano())))
  1086  		zrange = pipe.ZRange(keyName, 0, -1)
  1087  
  1088  		return nil
  1089  	}
  1090  
  1091  	var err error
  1092  	if pipeline {
  1093  		_, err = client.Pipelined(pipeFn)
  1094  	} else {
  1095  		_, err = client.TxPipelined(pipeFn)
  1096  	}
  1097  	if err != nil {
  1098  		log.Error("Multi command failed: ", err)
  1099  		return 0, nil
  1100  	}
  1101  
  1102  	values := zrange.Val()
  1103  
  1104  	// Check actual value
  1105  	if values == nil {
  1106  		return 0, nil
  1107  	}
  1108  
  1109  	intVal := len(values)
  1110  	result := make([]interface{}, intVal)
  1111  	for i, v := range values {
  1112  		result[i] = v
  1113  	}
  1114  
  1115  	log.Debug("Returned: ", intVal)
  1116  
  1117  	return intVal, result
  1118  }
  1119  
  1120  // GetPrefix returns storage key prefix
  1121  func (r *RedisCluster) GetKeyPrefix() string {
  1122  	return r.KeyPrefix
  1123  }
  1124  
  1125  // AddToSortedSet adds value with given score to sorted set identified by keyName
  1126  func (r *RedisCluster) AddToSortedSet(keyName, value string, score float64) {
  1127  	fixedKey := r.fixKey(keyName)
  1128  	logEntry := logrus.Fields{
  1129  		"keyName":  keyName,
  1130  		"fixedKey": fixedKey,
  1131  	}
  1132  	log.WithFields(logEntry).Debug("Pushing raw key to sorted set")
  1133  
  1134  	r.ensureConnection()
  1135  	member := redis.Z{Score: score, Member: value}
  1136  	if err := r.singleton().ZAdd(fixedKey, member).Err(); err != nil {
  1137  		log.WithFields(logEntry).WithError(err).Error("ZADD command failed")
  1138  	}
  1139  }
  1140  
  1141  // GetSortedSetRange gets range of elements of sorted set identified by keyName
  1142  func (r *RedisCluster) GetSortedSetRange(keyName, scoreFrom, scoreTo string) ([]string, []float64, error) {
  1143  	fixedKey := r.fixKey(keyName)
  1144  	logEntry := logrus.Fields{
  1145  		"keyName":   keyName,
  1146  		"fixedKey":  fixedKey,
  1147  		"scoreFrom": scoreFrom,
  1148  		"scoreTo":   scoreTo,
  1149  	}
  1150  	log.WithFields(logEntry).Debug("Getting sorted set range")
  1151  
  1152  	args := redis.ZRangeBy{Min: scoreFrom, Max: scoreTo}
  1153  	values, err := r.singleton().ZRangeByScoreWithScores(fixedKey, args).Result()
  1154  	if err != nil {
  1155  		log.WithFields(logEntry).WithError(err).Error("ZRANGEBYSCORE command failed")
  1156  		return nil, nil, err
  1157  	}
  1158  
  1159  	if len(values) == 0 {
  1160  		return nil, nil, nil
  1161  	}
  1162  
  1163  	elements := make([]string, len(values))
  1164  	scores := make([]float64, len(values))
  1165  
  1166  	for i, v := range values {
  1167  		elements[i] = fmt.Sprint(v.Member)
  1168  		scores[i] = v.Score
  1169  	}
  1170  
  1171  	return elements, scores, nil
  1172  }
  1173  
  1174  // RemoveSortedSetRange removes range of elements from sorted set identified by keyName
  1175  func (r *RedisCluster) RemoveSortedSetRange(keyName, scoreFrom, scoreTo string) error {
  1176  	fixedKey := r.fixKey(keyName)
  1177  	logEntry := logrus.Fields{
  1178  		"keyName":   keyName,
  1179  		"fixedKey":  fixedKey,
  1180  		"scoreFrom": scoreFrom,
  1181  		"scoreTo":   scoreTo,
  1182  	}
  1183  	log.WithFields(logEntry).Debug("Removing sorted set range")
  1184  
  1185  	if err := r.singleton().ZRemRangeByScore(fixedKey, scoreFrom, scoreTo).Err(); err != nil {
  1186  		log.WithFields(logEntry).WithError(err).Error("ZREMRANGEBYSCORE command failed")
  1187  		return err
  1188  	}
  1189  
  1190  	return nil
  1191  }