// NewClient creates a sentinel client. Connects to the given sentinel instance, // pulls the information for the masters of the given names, and creates an // intial pool of connections for each master. The client will automatically // replace the pool for any master should sentinel decide to fail the master // over. The returned error is a *ClientError. func NewClient( network, address string, poolSize int, names ...string, ) ( *Client, error, ) { // We use this to fetch initial details about masters before we upgrade it // to a pubsub client client, err := redis.Dial(network, address) if err != nil { return nil, &ClientError{err: err} } masterPools := map[string]*pool.Pool{} for _, name := range names { r := client.Cmd("SENTINEL", "MASTER", name) l, err := r.List() if err != nil { return nil, &ClientError{err: err, SentinelErr: true} } addr := l[3] + ":" + l[5] pool, err := pool.New("tcp", addr, poolSize) if err != nil { return nil, &ClientError{err: err} } masterPools[name] = pool } subClient := pubsub.NewSubClient(client) subSendErr := subClient.Subscribe("+switch-master") if subSendErr != nil { return nil, &ClientError{err: subSendErr, SentinelErr: true} } r := client.ReadResp() if r.Err != nil { return nil, &ClientError{err: r.Err, SentinelErr: true} } c := &Client{ poolSize: poolSize, masterPools: masterPools, subClient: subClient, getCh: make(chan *getReq), putCh: make(chan *putReq), closeCh: make(chan struct{}), alwaysErrCh: make(chan *ClientError), switchMasterCh: make(chan *switchMaster), } go c.subSpin() go c.spin() return c, nil }
// Similar to TestScan, but scans over a set instead of the whole key space func TestSScan(t *T) { client, err := redis.Dial("tcp", "127.0.0.1:6379") require.Nil(t, err) key := "scanTestSet" fullMap := map[string]bool{} for i := 0; i < 100; i++ { elem := strconv.Itoa(i) fullMap[elem] = true require.Nil(t, client.Cmd("SADD", key, elem).Err) } // make sure we get all results when scanning with an existing prefix ch := make(chan string) go func() { err = Scan(client, ch, "SSCAN", key, "*") }() testMap := map[string]bool{} for elem := range ch { testMap[elem] = true } require.Nil(t, err) assert.Equal(t, fullMap, testMap) // make sure we don't get any results when scanning with a non-existing // prefix ch = make(chan string) go func() { err = Scan(client, ch, "SSCAN", key+"DNE", "*") }() testMap = map[string]bool{} for elem := range ch { testMap[elem] = true } require.Nil(t, err) assert.Equal(t, map[string]bool{}, testMap) }
func TestScan(t *T) { client, err := redis.Dial("tcp", "127.0.0.1:6379") require.Nil(t, err) prefix := "scanTestPrefix" fullMap := map[string]bool{} for i := 0; i < 100; i++ { key := prefix + ":" + strconv.Itoa(i) fullMap[key] = true require.Nil(t, client.Cmd("SET", key, "1").Err) } // make sure we get all results when scanning with an existing prefix ch := make(chan string) go func() { err = Scan(client, ch, "SCAN", "", prefix+":*") }() testMap := map[string]bool{} for key := range ch { testMap[key] = true } require.Nil(t, err) assert.Equal(t, fullMap, testMap) // make sure we don't get any results when scanning with a non-existing // prefix ch = make(chan string) go func() { err = Scan(client, ch, "SCAN", "", prefix+"DNE:*") }() testMap = map[string]bool{} for key := range ch { testMap[key] = true } require.Nil(t, err) assert.Equal(t, map[string]bool{}, testMap) }