From f5593121e078b746f53a3574c7ff9e3409aba969 Mon Sep 17 00:00:00 2001 From: Vladimir Mihailenco Date: Wed, 11 Mar 2020 16:26:42 +0200 Subject: [PATCH 01/12] Add ctx as first arg --- bench_test.go | 86 +- cluster.go | 188 +-- cluster_commands.go | 13 +- cluster_test.go | 296 ++-- command.go | 195 ++- command_test.go | 28 +- commands.go | 2342 ++++++++++++++++--------------- commands_test.go | 1491 ++++++++++---------- example_instrumentation_test.go | 14 +- example_test.go | 118 +- export_test.go | 23 +- go.mod | 3 +- go.sum | 54 + internal/pool/conn.go | 39 +- internal/util.go | 47 +- iterator.go | 5 +- iterator_test.go | 44 +- main_test.go | 24 +- options.go | 9 +- pipeline.go | 29 +- pipeline_test.go | 22 +- pool_test.go | 20 +- pubsub.go | 106 +- pubsub_test.go | 130 +- race_test.go | 76 +- redis.go | 152 +- redis_test.go | 106 +- ring.go | 51 +- ring_test.go | 172 +-- script.go | 31 +- sentinel.go | 126 +- sentinel_test.go | 26 +- tx.go | 42 +- tx_test.go | 44 +- universal.go | 12 +- universal_test.go | 6 +- 36 files changed, 3200 insertions(+), 2970 deletions(-) diff --git a/bench_test.go b/bench_test.go index 1646724..c20f95d 100644 --- a/bench_test.go +++ b/bench_test.go @@ -11,7 +11,7 @@ import ( "github.com/go-redis/redis/v7" ) -func benchmarkRedisClient(poolSize int) *redis.Client { +func benchmarkRedisClient(ctx context.Context, poolSize int) *redis.Client { client := redis.NewClient(&redis.Options{ Addr: ":6379", DialTimeout: time.Second, @@ -19,21 +19,22 @@ func benchmarkRedisClient(poolSize int) *redis.Client { WriteTimeout: time.Second, PoolSize: poolSize, }) - if err := client.FlushDB().Err(); err != nil { + if err := client.FlushDB(ctx).Err(); err != nil { panic(err) } return client } func BenchmarkRedisPing(b *testing.B) { - client := benchmarkRedisClient(10) + ctx := context.Background() + client := benchmarkRedisClient(ctx, 10) defer client.Close() b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { - if err := client.Ping().Err(); err != nil { + if err := client.Ping(ctx).Err(); err != nil { b.Fatal(err) } } @@ -41,14 +42,15 @@ func BenchmarkRedisPing(b *testing.B) { } func BenchmarkRedisGetNil(b *testing.B) { - client := benchmarkRedisClient(10) + ctx := context.Background() + client := benchmarkRedisClient(ctx, 10) defer client.Close() b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { - if err := client.Get("key").Err(); err != redis.Nil { + if err := client.Get(ctx, "key").Err(); err != redis.Nil { b.Fatal(err) } } @@ -80,7 +82,8 @@ func BenchmarkRedisSetString(b *testing.B) { } for _, bm := range benchmarks { b.Run(bm.String(), func(b *testing.B) { - client := benchmarkRedisClient(bm.poolSize) + ctx := context.Background() + client := benchmarkRedisClient(ctx, bm.poolSize) defer client.Close() value := strings.Repeat("1", bm.valueSize) @@ -89,7 +92,7 @@ func BenchmarkRedisSetString(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { - err := client.Set("key", value, 0).Err() + err := client.Set(ctx, "key", value, 0).Err() if err != nil { b.Fatal(err) } @@ -100,7 +103,8 @@ func BenchmarkRedisSetString(b *testing.B) { } func BenchmarkRedisSetGetBytes(b *testing.B) { - client := benchmarkRedisClient(10) + ctx := context.Background() + client := benchmarkRedisClient(ctx, 10) defer client.Close() value := bytes.Repeat([]byte{'1'}, 10000) @@ -109,11 +113,11 @@ func BenchmarkRedisSetGetBytes(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { - if err := client.Set("key", value, 0).Err(); err != nil { + if err := client.Set(ctx, "key", value, 0).Err(); err != nil { b.Fatal(err) } - got, err := client.Get("key").Bytes() + got, err := client.Get(ctx, "key").Bytes() if err != nil { b.Fatal(err) } @@ -125,10 +129,11 @@ func BenchmarkRedisSetGetBytes(b *testing.B) { } func BenchmarkRedisMGet(b *testing.B) { - client := benchmarkRedisClient(10) + ctx := context.Background() + client := benchmarkRedisClient(ctx, 10) defer client.Close() - if err := client.MSet("key1", "hello1", "key2", "hello2").Err(); err != nil { + if err := client.MSet(ctx, "key1", "hello1", "key2", "hello2").Err(); err != nil { b.Fatal(err) } @@ -136,7 +141,7 @@ func BenchmarkRedisMGet(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { - if err := client.MGet("key1", "key2").Err(); err != nil { + if err := client.MGet(ctx, "key1", "key2").Err(); err != nil { b.Fatal(err) } } @@ -144,17 +149,18 @@ func BenchmarkRedisMGet(b *testing.B) { } func BenchmarkSetExpire(b *testing.B) { - client := benchmarkRedisClient(10) + ctx := context.Background() + client := benchmarkRedisClient(ctx, 10) defer client.Close() b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { - if err := client.Set("key", "hello", 0).Err(); err != nil { + if err := client.Set(ctx, "key", "hello", 0).Err(); err != nil { b.Fatal(err) } - if err := client.Expire("key", time.Second).Err(); err != nil { + if err := client.Expire(ctx, "key", time.Second).Err(); err != nil { b.Fatal(err) } } @@ -162,16 +168,17 @@ func BenchmarkSetExpire(b *testing.B) { } func BenchmarkPipeline(b *testing.B) { - client := benchmarkRedisClient(10) + ctx := context.Background() + client := benchmarkRedisClient(ctx, 10) defer client.Close() b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { - _, err := client.Pipelined(func(pipe redis.Pipeliner) error { - pipe.Set("key", "hello", 0) - pipe.Expire("key", time.Second) + _, err := client.Pipelined(ctx, func(pipe redis.Pipeliner) error { + pipe.Set(ctx, "key", "hello", 0) + pipe.Expire(ctx, "key", time.Second) return nil }) if err != nil { @@ -182,14 +189,15 @@ func BenchmarkPipeline(b *testing.B) { } func BenchmarkZAdd(b *testing.B) { - client := benchmarkRedisClient(10) + ctx := context.Background() + client := benchmarkRedisClient(ctx, 10) defer client.Close() b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { - err := client.ZAdd("key", &redis.Z{ + err := client.ZAdd(ctx, "key", &redis.Z{ Score: float64(1), Member: "hello", }).Err() @@ -203,10 +211,9 @@ func BenchmarkZAdd(b *testing.B) { var clientSink *redis.Client func BenchmarkWithContext(b *testing.B) { - rdb := benchmarkRedisClient(10) - defer rdb.Close() - ctx := context.Background() + rdb := benchmarkRedisClient(ctx, 10) + defer rdb.Close() b.ResetTimer() b.ReportAllocs() @@ -219,11 +226,10 @@ func BenchmarkWithContext(b *testing.B) { var ringSink *redis.Ring func BenchmarkRingWithContext(b *testing.B) { + ctx := context.Background() rdb := redis.NewRing(&redis.RingOptions{}) defer rdb.Close() - ctx := context.Background() - b.ResetTimer() b.ReportAllocs() @@ -248,20 +254,21 @@ func BenchmarkClusterPing(b *testing.B) { b.Skip("skipping in short mode") } + ctx := context.Background() cluster := newClusterScenario() - if err := startCluster(cluster); err != nil { + if err := startCluster(ctx, cluster); err != nil { b.Fatal(err) } defer stopCluster(cluster) - client := cluster.newClusterClient(redisClusterOptions()) + client := cluster.newClusterClient(ctx, redisClusterOptions()) defer client.Close() b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { - err := client.Ping().Err() + err := client.Ping(ctx).Err() if err != nil { b.Fatal(err) } @@ -274,13 +281,14 @@ func BenchmarkClusterSetString(b *testing.B) { b.Skip("skipping in short mode") } + ctx := context.Background() cluster := newClusterScenario() - if err := startCluster(cluster); err != nil { + if err := startCluster(ctx, cluster); err != nil { b.Fatal(err) } defer stopCluster(cluster) - client := cluster.newClusterClient(redisClusterOptions()) + client := cluster.newClusterClient(ctx, redisClusterOptions()) defer client.Close() value := string(bytes.Repeat([]byte{'1'}, 10000)) @@ -289,7 +297,7 @@ func BenchmarkClusterSetString(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { - err := client.Set("key", value, 0).Err() + err := client.Set(ctx, "key", value, 0).Err() if err != nil { b.Fatal(err) } @@ -302,19 +310,20 @@ func BenchmarkClusterReloadState(b *testing.B) { b.Skip("skipping in short mode") } + ctx := context.Background() cluster := newClusterScenario() - if err := startCluster(cluster); err != nil { + if err := startCluster(ctx, cluster); err != nil { b.Fatal(err) } defer stopCluster(cluster) - client := cluster.newClusterClient(redisClusterOptions()) + client := cluster.newClusterClient(ctx, redisClusterOptions()) defer client.Close() b.ResetTimer() for i := 0; i < b.N; i++ { - err := client.ReloadState() + err := client.ReloadState(ctx) if err != nil { b.Fatal(err) } @@ -324,11 +333,10 @@ func BenchmarkClusterReloadState(b *testing.B) { var clusterSink *redis.ClusterClient func BenchmarkClusterWithContext(b *testing.B) { + ctx := context.Background() rdb := redis.NewClusterClient(&redis.ClusterOptions{}) defer rdb.Close() - ctx := context.Background() - b.ResetTimer() b.ReportAllocs() diff --git a/cluster.go b/cluster.go index 2cf6e01..31eed3d 100644 --- a/cluster.go +++ b/cluster.go @@ -191,7 +191,7 @@ func (n *clusterNode) updateLatency() { var latency uint32 for i := 0; i < probes; i++ { start := time.Now() - n.Client.Ping() + n.Client.Ping(context.TODO()) probe := uint32(time.Since(start) / time.Microsecond) latency = (latency + probe) / 2 } @@ -588,20 +588,20 @@ func (c *clusterState) slotNodes(slot int) []*clusterNode { //------------------------------------------------------------------------------ type clusterStateHolder struct { - load func() (*clusterState, error) + load func(ctx context.Context) (*clusterState, error) state atomic.Value reloading uint32 // atomic } -func newClusterStateHolder(fn func() (*clusterState, error)) *clusterStateHolder { +func newClusterStateHolder(fn func(ctx context.Context) (*clusterState, error)) *clusterStateHolder { return &clusterStateHolder{ load: fn, } } -func (c *clusterStateHolder) Reload() (*clusterState, error) { - state, err := c.load() +func (c *clusterStateHolder) Reload(ctx context.Context) (*clusterState, error) { + state, err := c.load(ctx) if err != nil { return nil, err } @@ -609,14 +609,14 @@ func (c *clusterStateHolder) Reload() (*clusterState, error) { return state, nil } -func (c *clusterStateHolder) LazyReload() { +func (c *clusterStateHolder) LazyReload(ctx context.Context) { if !atomic.CompareAndSwapUint32(&c.reloading, 0, 1) { return } go func() { defer atomic.StoreUint32(&c.reloading, 0) - _, err := c.Reload() + _, err := c.Reload(ctx) if err != nil { return } @@ -624,24 +624,24 @@ func (c *clusterStateHolder) LazyReload() { }() } -func (c *clusterStateHolder) Get() (*clusterState, error) { +func (c *clusterStateHolder) Get(ctx context.Context) (*clusterState, error) { v := c.state.Load() if v != nil { state := v.(*clusterState) if time.Since(state.createdAt) > time.Minute { - c.LazyReload() + c.LazyReload(ctx) } return state, nil } - return c.Reload() + return c.Reload(ctx) } -func (c *clusterStateHolder) ReloadOrGet() (*clusterState, error) { - state, err := c.Reload() +func (c *clusterStateHolder) ReloadOrGet(ctx context.Context) (*clusterState, error) { + state, err := c.Reload(ctx) if err == nil { return state, nil } - return c.Get() + return c.Get(ctx) } //------------------------------------------------------------------------------ @@ -708,8 +708,8 @@ func (c *ClusterClient) Options() *ClusterOptions { // ReloadState reloads cluster state. If available it calls ClusterSlots func // to get cluster slots information. -func (c *ClusterClient) ReloadState() error { - _, err := c.state.Reload() +func (c *ClusterClient) ReloadState(ctx context.Context) error { + _, err := c.state.Reload(ctx) return err } @@ -722,21 +722,13 @@ func (c *ClusterClient) Close() error { } // Do creates a Cmd from the args and processes the cmd. -func (c *ClusterClient) Do(args ...interface{}) *Cmd { - return c.DoContext(c.ctx, args...) -} - -func (c *ClusterClient) DoContext(ctx context.Context, args ...interface{}) *Cmd { - cmd := NewCmd(args...) - _ = c.ProcessContext(ctx, cmd) +func (c *ClusterClient) Do(ctx context.Context, args ...interface{}) *Cmd { + cmd := NewCmd(ctx, args...) + _ = c.Process(ctx, cmd) return cmd } -func (c *ClusterClient) Process(cmd Cmder) error { - return c.ProcessContext(c.ctx, cmd) -} - -func (c *ClusterClient) ProcessContext(ctx context.Context, cmd Cmder) error { +func (c *ClusterClient) Process(ctx context.Context, cmd Cmder) error { return c.hooks.process(ctx, cmd, c.process) } @@ -765,7 +757,7 @@ func (c *ClusterClient) _process(ctx context.Context, cmd Cmder) error { if node == nil { var err error - node, err = c.cmdNode(cmdInfo, slot) + node, err = c.cmdNode(ctx, cmdInfo, slot) if err != nil { return err } @@ -773,13 +765,13 @@ func (c *ClusterClient) _process(ctx context.Context, cmd Cmder) error { if ask { pipe := node.Client.Pipeline() - _ = pipe.Process(NewCmd("asking")) - _ = pipe.Process(cmd) - _, lastErr = pipe.ExecContext(ctx) + _ = pipe.Process(ctx, NewCmd(ctx, "asking")) + _ = pipe.Process(ctx, cmd) + _, lastErr = pipe.Exec(ctx) _ = pipe.Close() ask = false } else { - lastErr = node.Client.ProcessContext(ctx, cmd) + lastErr = node.Client.Process(ctx, cmd) } // If there is no error - we are done. @@ -787,7 +779,7 @@ func (c *ClusterClient) _process(ctx context.Context, cmd Cmder) error { return nil } if lastErr != Nil { - c.state.LazyReload() + c.state.LazyReload(ctx) } if lastErr == pool.ErrClosed || isReadOnlyError(lastErr) { node = nil @@ -832,8 +824,11 @@ func (c *ClusterClient) _process(ctx context.Context, cmd Cmder) error { // ForEachMaster concurrently calls the fn on each master node in the cluster. // It returns the first error if any. -func (c *ClusterClient) ForEachMaster(fn func(client *Client) error) error { - state, err := c.state.ReloadOrGet() +func (c *ClusterClient) ForEachMaster( + ctx context.Context, + fn func(ctx context.Context, client *Client) error, +) error { + state, err := c.state.ReloadOrGet(ctx) if err != nil { return err } @@ -845,7 +840,7 @@ func (c *ClusterClient) ForEachMaster(fn func(client *Client) error) error { wg.Add(1) go func(node *clusterNode) { defer wg.Done() - err := fn(node.Client) + err := fn(ctx, node.Client) if err != nil { select { case errCh <- err: @@ -867,8 +862,11 @@ func (c *ClusterClient) ForEachMaster(fn func(client *Client) error) error { // ForEachSlave concurrently calls the fn on each slave node in the cluster. // It returns the first error if any. -func (c *ClusterClient) ForEachSlave(fn func(client *Client) error) error { - state, err := c.state.ReloadOrGet() +func (c *ClusterClient) ForEachSlave( + ctx context.Context, + fn func(ctx context.Context, client *Client) error, +) error { + state, err := c.state.ReloadOrGet(ctx) if err != nil { return err } @@ -880,7 +878,7 @@ func (c *ClusterClient) ForEachSlave(fn func(client *Client) error) error { wg.Add(1) go func(node *clusterNode) { defer wg.Done() - err := fn(node.Client) + err := fn(ctx, node.Client) if err != nil { select { case errCh <- err: @@ -902,8 +900,11 @@ func (c *ClusterClient) ForEachSlave(fn func(client *Client) error) error { // ForEachNode concurrently calls the fn on each known node in the cluster. // It returns the first error if any. -func (c *ClusterClient) ForEachNode(fn func(client *Client) error) error { - state, err := c.state.ReloadOrGet() +func (c *ClusterClient) ForEachNode( + ctx context.Context, + fn func(ctx context.Context, client *Client) error, +) error { + state, err := c.state.ReloadOrGet(ctx) if err != nil { return err } @@ -913,7 +914,7 @@ func (c *ClusterClient) ForEachNode(fn func(client *Client) error) error { worker := func(node *clusterNode) { defer wg.Done() - err := fn(node.Client) + err := fn(ctx, node.Client) if err != nil { select { case errCh <- err: @@ -945,7 +946,7 @@ func (c *ClusterClient) ForEachNode(fn func(client *Client) error) error { func (c *ClusterClient) PoolStats() *PoolStats { var acc PoolStats - state, _ := c.state.Get() + state, _ := c.state.Get(context.TODO()) if state == nil { return &acc } @@ -975,7 +976,7 @@ func (c *ClusterClient) PoolStats() *PoolStats { return &acc } -func (c *ClusterClient) loadState() (*clusterState, error) { +func (c *ClusterClient) loadState(ctx context.Context) (*clusterState, error) { if c.opt.ClusterSlots != nil { slots, err := c.opt.ClusterSlots() if err != nil { @@ -999,7 +1000,7 @@ func (c *ClusterClient) loadState() (*clusterState, error) { continue } - slots, err := node.Client.ClusterSlots().Result() + slots, err := node.Client.ClusterSlots(ctx).Result() if err != nil { if firstErr == nil { firstErr = err @@ -1042,8 +1043,8 @@ func (c *ClusterClient) Pipeline() Pipeliner { return &pipe } -func (c *ClusterClient) Pipelined(fn func(Pipeliner) error) ([]Cmder, error) { - return c.Pipeline().Pipelined(fn) +func (c *ClusterClient) Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) { + return c.Pipeline().Pipelined(ctx, fn) } func (c *ClusterClient) processPipeline(ctx context.Context, cmds []Cmder) error { @@ -1052,7 +1053,7 @@ func (c *ClusterClient) processPipeline(ctx context.Context, cmds []Cmder) error func (c *ClusterClient) _processPipeline(ctx context.Context, cmds []Cmder) error { cmdsMap := newCmdsMap() - err := c.mapCmdsByNode(cmdsMap, cmds) + err := c.mapCmdsByNode(ctx, cmdsMap, cmds) if err != nil { setCmdsErr(cmds, err) return err @@ -1079,7 +1080,7 @@ func (c *ClusterClient) _processPipeline(ctx context.Context, cmds []Cmder) erro return } if attempt < c.opt.MaxRedirects { - if err := c.mapCmdsByNode(failedCmds, cmds); err != nil { + if err := c.mapCmdsByNode(ctx, failedCmds, cmds); err != nil { setCmdsErr(cmds, err) } } else { @@ -1098,8 +1099,8 @@ func (c *ClusterClient) _processPipeline(ctx context.Context, cmds []Cmder) erro return cmdsFirstErr(cmds) } -func (c *ClusterClient) mapCmdsByNode(cmdsMap *cmdsMap, cmds []Cmder) error { - state, err := c.state.Get() +func (c *ClusterClient) mapCmdsByNode(ctx context.Context, cmdsMap *cmdsMap, cmds []Cmder) error { + state, err := c.state.Get(ctx) if err != nil { return err } @@ -1150,21 +1151,25 @@ func (c *ClusterClient) _processPipelineNode( } return cn.WithReader(ctx, c.opt.ReadTimeout, func(rd *proto.Reader) error { - return c.pipelineReadCmds(node, rd, cmds, failedCmds) + return c.pipelineReadCmds(ctx, node, rd, cmds, failedCmds) }) }) }) } func (c *ClusterClient) pipelineReadCmds( - node *clusterNode, rd *proto.Reader, cmds []Cmder, failedCmds *cmdsMap, + ctx context.Context, + node *clusterNode, + rd *proto.Reader, + cmds []Cmder, + failedCmds *cmdsMap, ) error { for _, cmd := range cmds { err := cmd.readReply(rd) if err == nil { continue } - if c.checkMovedErr(cmd, err, failedCmds) { + if c.checkMovedErr(ctx, cmd, err, failedCmds) { continue } @@ -1181,7 +1186,7 @@ func (c *ClusterClient) pipelineReadCmds( } func (c *ClusterClient) checkMovedErr( - cmd Cmder, err error, failedCmds *cmdsMap, + ctx context.Context, cmd Cmder, err error, failedCmds *cmdsMap, ) bool { moved, ask, addr := isMovedError(err) if !moved && !ask { @@ -1194,13 +1199,13 @@ func (c *ClusterClient) checkMovedErr( } if moved { - c.state.LazyReload() + c.state.LazyReload(ctx) failedCmds.Add(node, cmd) return true } if ask { - failedCmds.Add(node, NewCmd("asking"), cmd) + failedCmds.Add(node, NewCmd(ctx, "asking"), cmd) return true } @@ -1217,8 +1222,8 @@ func (c *ClusterClient) TxPipeline() Pipeliner { return &pipe } -func (c *ClusterClient) TxPipelined(fn func(Pipeliner) error) ([]Cmder, error) { - return c.TxPipeline().Pipelined(fn) +func (c *ClusterClient) TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) { + return c.TxPipeline().Pipelined(ctx, fn) } func (c *ClusterClient) processTxPipeline(ctx context.Context, cmds []Cmder) error { @@ -1226,7 +1231,7 @@ func (c *ClusterClient) processTxPipeline(ctx context.Context, cmds []Cmder) err } func (c *ClusterClient) _processTxPipeline(ctx context.Context, cmds []Cmder) error { - state, err := c.state.Get() + state, err := c.state.Get(ctx) if err != nil { setCmdsErr(cmds, err) return err @@ -1262,7 +1267,7 @@ func (c *ClusterClient) _processTxPipeline(ctx context.Context, cmds []Cmder) er return } if attempt < c.opt.MaxRedirects { - if err := c.mapCmdsByNode(failedCmds, cmds); err != nil { + if err := c.mapCmdsByNode(ctx, failedCmds, cmds); err != nil { setCmdsErr(cmds, err) } } else { @@ -1308,11 +1313,11 @@ func (c *ClusterClient) _processTxPipelineNode( // Trim multi and exec. cmds = cmds[1 : len(cmds)-1] - err := c.txPipelineReadQueued(rd, statusCmd, cmds, failedCmds) + err := c.txPipelineReadQueued(ctx, rd, statusCmd, cmds, failedCmds) if err != nil { moved, ask, addr := isMovedError(err) if moved || ask { - return c.cmdsMoved(cmds, moved, ask, addr, failedCmds) + return c.cmdsMoved(ctx, cmds, moved, ask, addr, failedCmds) } return err } @@ -1324,7 +1329,11 @@ func (c *ClusterClient) _processTxPipelineNode( } func (c *ClusterClient) txPipelineReadQueued( - rd *proto.Reader, statusCmd *StatusCmd, cmds []Cmder, failedCmds *cmdsMap, + ctx context.Context, + rd *proto.Reader, + statusCmd *StatusCmd, + cmds []Cmder, + failedCmds *cmdsMap, ) error { // Parse queued replies. if err := statusCmd.readReply(rd); err != nil { @@ -1333,7 +1342,7 @@ func (c *ClusterClient) txPipelineReadQueued( for _, cmd := range cmds { err := statusCmd.readReply(rd) - if err == nil || c.checkMovedErr(cmd, err, failedCmds) || isRedisError(err) { + if err == nil || c.checkMovedErr(ctx, cmd, err, failedCmds) || isRedisError(err) { continue } return err @@ -1361,7 +1370,10 @@ func (c *ClusterClient) txPipelineReadQueued( } func (c *ClusterClient) cmdsMoved( - cmds []Cmder, moved, ask bool, addr string, failedCmds *cmdsMap, + ctx context.Context, cmds []Cmder, + moved, ask bool, + addr string, + failedCmds *cmdsMap, ) error { node, err := c.nodes.Get(addr) if err != nil { @@ -1369,7 +1381,7 @@ func (c *ClusterClient) cmdsMoved( } if moved { - c.state.LazyReload() + c.state.LazyReload(ctx) for _, cmd := range cmds { failedCmds.Add(node, cmd) } @@ -1378,7 +1390,7 @@ func (c *ClusterClient) cmdsMoved( if ask { for _, cmd := range cmds { - failedCmds.Add(node, NewCmd("asking"), cmd) + failedCmds.Add(node, NewCmd(ctx, "asking"), cmd) } return nil } @@ -1386,11 +1398,7 @@ func (c *ClusterClient) cmdsMoved( return nil } -func (c *ClusterClient) Watch(fn func(*Tx) error, keys ...string) error { - return c.WatchContext(c.ctx, fn, keys...) -} - -func (c *ClusterClient) WatchContext(ctx context.Context, fn func(*Tx) error, keys ...string) error { +func (c *ClusterClient) Watch(ctx context.Context, fn func(*Tx) error, keys ...string) error { if len(keys) == 0 { return fmt.Errorf("redis: Watch requires at least one key") } @@ -1403,7 +1411,7 @@ func (c *ClusterClient) WatchContext(ctx context.Context, fn func(*Tx) error, ke } } - node, err := c.slotMasterNode(slot) + node, err := c.slotMasterNode(ctx, slot) if err != nil { return err } @@ -1415,12 +1423,12 @@ func (c *ClusterClient) WatchContext(ctx context.Context, fn func(*Tx) error, ke } } - err = node.Client.WatchContext(ctx, fn, keys...) + err = node.Client.Watch(ctx, fn, keys...) if err == nil { break } if err != Nil { - c.state.LazyReload() + c.state.LazyReload(ctx) } moved, ask, addr := isMovedError(err) @@ -1433,7 +1441,7 @@ func (c *ClusterClient) WatchContext(ctx context.Context, fn func(*Tx) error, ke } if err == pool.ErrClosed || isReadOnlyError(err) { - node, err = c.slotMasterNode(slot) + node, err = c.slotMasterNode(ctx, slot) if err != nil { return err } @@ -1455,7 +1463,7 @@ func (c *ClusterClient) pubSub() *PubSub { pubsub := &PubSub{ opt: c.opt.clientOptions(), - newConn: func(channels []string) (*pool.Conn, error) { + newConn: func(ctx context.Context, channels []string) (*pool.Conn, error) { if node != nil { panic("node != nil") } @@ -1463,7 +1471,7 @@ func (c *ClusterClient) pubSub() *PubSub { var err error if len(channels) > 0 { slot := hashtag.Slot(channels[0]) - node, err = c.slotMasterNode(slot) + node, err = c.slotMasterNode(ctx, slot) } else { node, err = c.nodes.Random() } @@ -1493,20 +1501,20 @@ func (c *ClusterClient) pubSub() *PubSub { // Subscribe subscribes the client to the specified channels. // Channels can be omitted to create empty subscription. -func (c *ClusterClient) Subscribe(channels ...string) *PubSub { +func (c *ClusterClient) Subscribe(ctx context.Context, channels ...string) *PubSub { pubsub := c.pubSub() if len(channels) > 0 { - _ = pubsub.Subscribe(channels...) + _ = pubsub.Subscribe(ctx, channels...) } return pubsub } // PSubscribe subscribes the client to the given patterns. // Patterns can be omitted to create empty subscription. -func (c *ClusterClient) PSubscribe(channels ...string) *PubSub { +func (c *ClusterClient) PSubscribe(ctx context.Context, channels ...string) *PubSub { pubsub := c.pubSub() if len(channels) > 0 { - _ = pubsub.PSubscribe(channels...) + _ = pubsub.PSubscribe(ctx, channels...) } return pubsub } @@ -1531,7 +1539,7 @@ func (c *ClusterClient) cmdsInfo() (map[string]*CommandInfo, error) { continue } - info, err := node.Client.Command().Result() + info, err := node.Client.Command(context.TODO()).Result() if err == nil { return info, nil } @@ -1573,8 +1581,12 @@ func cmdSlot(cmd Cmder, pos int) int { return hashtag.Slot(firstKey) } -func (c *ClusterClient) cmdNode(cmdInfo *CommandInfo, slot int) (*clusterNode, error) { - state, err := c.state.Get() +func (c *ClusterClient) cmdNode( + ctx context.Context, + cmdInfo *CommandInfo, + slot int, +) (*clusterNode, error) { + state, err := c.state.Get(ctx) if err != nil { return nil, err } @@ -1595,8 +1607,8 @@ func (c *clusterClient) slotReadOnlyNode(state *clusterState, slot int) (*cluste return state.slotSlaveNode(slot) } -func (c *ClusterClient) slotMasterNode(slot int) (*clusterNode, error) { - state, err := c.state.Get() +func (c *ClusterClient) slotMasterNode(ctx context.Context, slot int) (*clusterNode, error) { + state, err := c.state.Get(ctx) if err != nil { return nil, err } diff --git a/cluster_commands.go b/cluster_commands.go index c9b9b9d..1f0bae0 100644 --- a/cluster_commands.go +++ b/cluster_commands.go @@ -1,12 +1,15 @@ package redis -import "sync/atomic" +import ( + "context" + "sync/atomic" +) -func (c *ClusterClient) DBSize() *IntCmd { - cmd := NewIntCmd("dbsize") +func (c *ClusterClient) DBSize(ctx context.Context) *IntCmd { + cmd := NewIntCmd(ctx, "dbsize") var size int64 - err := c.ForEachMaster(func(master *Client) error { - n, err := master.DBSize().Result() + err := c.ForEachMaster(ctx, func(ctx context.Context, master *Client) error { + n, err := master.DBSize(ctx).Result() if err != nil { return err } diff --git a/cluster_test.go b/cluster_test.go index 62fd6e0..83e120d 100644 --- a/cluster_test.go +++ b/cluster_test.go @@ -53,7 +53,9 @@ func (s *clusterScenario) newClusterClientUnsafe(opt *redis.ClusterOptions) *red } -func (s *clusterScenario) newClusterClient(opt *redis.ClusterOptions) *redis.ClusterClient { +func (s *clusterScenario) newClusterClient( + ctx context.Context, opt *redis.ClusterOptions, +) *redis.ClusterClient { client := s.newClusterClientUnsafe(opt) err := eventually(func() error { @@ -61,12 +63,12 @@ func (s *clusterScenario) newClusterClient(opt *redis.ClusterOptions) *redis.Clu return nil } - state, err := client.LoadState() + state, err := client.LoadState(ctx) if err != nil { return err } - if !state.IsConsistent() { + if !state.IsConsistent(ctx) { return fmt.Errorf("cluster state is not consistent") } @@ -79,7 +81,7 @@ func (s *clusterScenario) newClusterClient(opt *redis.ClusterOptions) *redis.Clu return client } -func startCluster(scenario *clusterScenario) error { +func startCluster(ctx context.Context, scenario *clusterScenario) error { // Start processes and collect node ids for pos, port := range scenario.ports { process, err := startRedis(port, "--cluster-enabled", "yes") @@ -91,7 +93,7 @@ func startCluster(scenario *clusterScenario) error { Addr: ":" + port, }) - info, err := client.ClusterNodes().Result() + info, err := client.ClusterNodes(ctx).Result() if err != nil { return err } @@ -103,7 +105,7 @@ func startCluster(scenario *clusterScenario) error { // Meet cluster nodes. for _, client := range scenario.clients { - err := client.ClusterMeet("127.0.0.1", scenario.ports[0]).Err() + err := client.ClusterMeet(ctx, "127.0.0.1", scenario.ports[0]).Err() if err != nil { return err } @@ -112,7 +114,7 @@ func startCluster(scenario *clusterScenario) error { // Bootstrap masters. slots := []int{0, 5000, 10000, 16384} for pos, master := range scenario.masters() { - err := master.ClusterAddSlotsRange(slots[pos], slots[pos+1]-1).Err() + err := master.ClusterAddSlotsRange(ctx, slots[pos], slots[pos+1]-1).Err() if err != nil { return err } @@ -124,7 +126,7 @@ func startCluster(scenario *clusterScenario) error { // Wait until master is available err := eventually(func() error { - s := slave.ClusterNodes().Val() + s := slave.ClusterNodes(ctx).Val() wanted := masterID if !strings.Contains(s, wanted) { return fmt.Errorf("%q does not contain %q", s, wanted) @@ -135,7 +137,7 @@ func startCluster(scenario *clusterScenario) error { return err } - err = slave.ClusterReplicate(masterID).Err() + err = slave.ClusterReplicate(ctx, masterID).Err() if err != nil { return err } @@ -175,7 +177,7 @@ func startCluster(scenario *clusterScenario) error { }} for _, client := range scenario.clients { err := eventually(func() error { - res, err := client.ClusterSlots().Result() + res, err := client.ClusterSlots(ctx).Result() if err != nil { return err } @@ -243,48 +245,48 @@ var _ = Describe("ClusterClient", func() { assertClusterClient := func() { It("supports WithContext", func() { - c, cancel := context.WithCancel(context.Background()) + ctx, cancel := context.WithCancel(ctx) cancel() - err := client.WithContext(c).Ping().Err() + err := client.Ping(ctx).Err() Expect(err).To(MatchError("context canceled")) }) It("should GET/SET/DEL", func() { - err := client.Get("A").Err() + err := client.Get(ctx, "A").Err() Expect(err).To(Equal(redis.Nil)) - err = client.Set("A", "VALUE", 0).Err() + err = client.Set(ctx, "A", "VALUE", 0).Err() Expect(err).NotTo(HaveOccurred()) Eventually(func() string { - return client.Get("A").Val() + return client.Get(ctx, "A").Val() }, 30*time.Second).Should(Equal("VALUE")) - cnt, err := client.Del("A").Result() + cnt, err := client.Del(ctx, "A").Result() Expect(err).NotTo(HaveOccurred()) Expect(cnt).To(Equal(int64(1))) }) It("GET follows redirects", func() { - err := client.Set("A", "VALUE", 0).Err() + err := client.Set(ctx, "A", "VALUE", 0).Err() Expect(err).NotTo(HaveOccurred()) if !failover { Eventually(func() int64 { - nodes, err := client.Nodes("A") + nodes, err := client.Nodes(ctx, "A") if err != nil { return 0 } - return nodes[1].Client.DBSize().Val() + return nodes[1].Client.DBSize(ctx).Val() }, 30*time.Second).Should(Equal(int64(1))) Eventually(func() error { - return client.SwapNodes("A") + return client.SwapNodes(ctx, "A") }, 30*time.Second).ShouldNot(HaveOccurred()) } - v, err := client.Get("A").Result() + v, err := client.Get(ctx, "A").Result() Expect(err).NotTo(HaveOccurred()) Expect(v).To(Equal("VALUE")) }) @@ -292,28 +294,28 @@ var _ = Describe("ClusterClient", func() { It("SET follows redirects", func() { if !failover { Eventually(func() error { - return client.SwapNodes("A") + return client.SwapNodes(ctx, "A") }, 30*time.Second).ShouldNot(HaveOccurred()) } - err := client.Set("A", "VALUE", 0).Err() + err := client.Set(ctx, "A", "VALUE", 0).Err() Expect(err).NotTo(HaveOccurred()) - v, err := client.Get("A").Result() + v, err := client.Get(ctx, "A").Result() Expect(err).NotTo(HaveOccurred()) Expect(v).To(Equal("VALUE")) }) It("distributes keys", func() { for i := 0; i < 100; i++ { - err := client.Set(fmt.Sprintf("key%d", i), "value", 0).Err() + err := client.Set(ctx, fmt.Sprintf("key%d", i), "value", 0).Err() Expect(err).NotTo(HaveOccurred()) } - client.ForEachMaster(func(master *redis.Client) error { + client.ForEachMaster(ctx, func(ctx context.Context, master *redis.Client) error { defer GinkgoRecover() Eventually(func() string { - return master.Info("keyspace").Val() + return master.Info(ctx, "keyspace").Val() }, 30*time.Second).Should(Or( ContainSubstring("keys=31"), ContainSubstring("keys=29"), @@ -332,14 +334,14 @@ var _ = Describe("ClusterClient", func() { var key string for i := 0; i < 100; i++ { key = fmt.Sprintf("key%d", i) - err := script.Run(client, []string{key}, "value").Err() + err := script.Run(ctx, client, []string{key}, "value").Err() Expect(err).NotTo(HaveOccurred()) } - client.ForEachMaster(func(master *redis.Client) error { + client.ForEachMaster(ctx, func(ctx context.Context, master *redis.Client) error { defer GinkgoRecover() Eventually(func() string { - return master.Info("keyspace").Val() + return master.Info(ctx, "keyspace").Val() }, 30*time.Second).Should(Or( ContainSubstring("keys=31"), ContainSubstring("keys=29"), @@ -354,14 +356,14 @@ var _ = Describe("ClusterClient", func() { // Transactionally increments key using GET and SET commands. incr = func(key string) error { - err := client.Watch(func(tx *redis.Tx) error { - n, err := tx.Get(key).Int64() + err := client.Watch(ctx, func(tx *redis.Tx) error { + n, err := tx.Get(ctx, key).Int64() if err != nil && err != redis.Nil { return err } - _, err = tx.TxPipelined(func(pipe redis.Pipeliner) error { - pipe.Set(key, strconv.FormatInt(n+1, 10), 0) + _, err = tx.TxPipelined(ctx, func(pipe redis.Pipeliner) error { + pipe.Set(ctx, key, strconv.FormatInt(n+1, 10), 0) return nil }) return err @@ -386,7 +388,7 @@ var _ = Describe("ClusterClient", func() { wg.Wait() Eventually(func() string { - return client.Get("key").Val() + return client.Get(ctx, "key").Val() }, 30*time.Second).Should(Equal("100")) }) @@ -400,23 +402,23 @@ var _ = Describe("ClusterClient", func() { if !failover { for _, key := range keys { Eventually(func() error { - return client.SwapNodes(key) + return client.SwapNodes(ctx, key) }, 30*time.Second).ShouldNot(HaveOccurred()) } } for i, key := range keys { - pipe.Set(key, key+"_value", 0) - pipe.Expire(key, time.Duration(i+1)*time.Hour) + pipe.Set(ctx, key, key+"_value", 0) + pipe.Expire(ctx, key, time.Duration(i+1)*time.Hour) } - cmds, err := pipe.Exec() + cmds, err := pipe.Exec(ctx) Expect(err).NotTo(HaveOccurred()) Expect(cmds).To(HaveLen(14)) - _ = client.ForEachNode(func(node *redis.Client) error { + _ = client.ForEachNode(ctx, func(ctx context.Context, node *redis.Client) error { defer GinkgoRecover() Eventually(func() int64 { - return node.DBSize().Val() + return node.DBSize(ctx).Val() }, 30*time.Second).ShouldNot(BeZero()) return nil }) @@ -424,16 +426,16 @@ var _ = Describe("ClusterClient", func() { if !failover { for _, key := range keys { Eventually(func() error { - return client.SwapNodes(key) + return client.SwapNodes(ctx, key) }, 30*time.Second).ShouldNot(HaveOccurred()) } } for _, key := range keys { - pipe.Get(key) - pipe.TTL(key) + pipe.Get(ctx, key) + pipe.TTL(ctx, key) } - cmds, err = pipe.Exec() + cmds, err = pipe.Exec(ctx) Expect(err).NotTo(HaveOccurred()) Expect(cmds).To(HaveLen(14)) @@ -448,15 +450,15 @@ var _ = Describe("ClusterClient", func() { }) It("works with missing keys", func() { - pipe.Set("A", "A_value", 0) - pipe.Set("C", "C_value", 0) - _, err := pipe.Exec() + pipe.Set(ctx, "A", "A_value", 0) + pipe.Set(ctx, "C", "C_value", 0) + _, err := pipe.Exec(ctx) Expect(err).NotTo(HaveOccurred()) - a := pipe.Get("A") - b := pipe.Get("B") - c := pipe.Get("C") - cmds, err := pipe.Exec() + a := pipe.Get(ctx, "A") + b := pipe.Get(ctx, "B") + c := pipe.Get(ctx, "C") + cmds, err := pipe.Exec(ctx) Expect(err).To(Equal(redis.Nil)) Expect(cmds).To(HaveLen(3)) @@ -497,16 +499,16 @@ var _ = Describe("ClusterClient", func() { }) It("supports PubSub", func() { - pubsub := client.Subscribe("mychannel") + pubsub := client.Subscribe(ctx, "mychannel") defer pubsub.Close() Eventually(func() error { - _, err := client.Publish("mychannel", "hello").Result() + _, err := client.Publish(ctx, "mychannel", "hello").Result() if err != nil { return err } - msg, err := pubsub.ReceiveTimeout(time.Second) + msg, err := pubsub.ReceiveTimeout(ctx, time.Second) if err != nil { return err } @@ -521,19 +523,19 @@ var _ = Describe("ClusterClient", func() { }) It("supports PubSub.Ping without channels", func() { - pubsub := client.Subscribe() + pubsub := client.Subscribe(ctx) defer pubsub.Close() - err := pubsub.Ping() + err := pubsub.Ping(ctx) Expect(err).NotTo(HaveOccurred()) }) It("supports Process hook", func() { - err := client.Ping().Err() + err := client.Ping(ctx).Err() Expect(err).NotTo(HaveOccurred()) - err = client.ForEachNode(func(node *redis.Client) error { - return node.Ping().Err() + err = client.ForEachNode(ctx, func(ctx context.Context, node *redis.Client) error { + return node.Ping(ctx).Err() }) Expect(err).NotTo(HaveOccurred()) @@ -566,12 +568,12 @@ var _ = Describe("ClusterClient", func() { }, } - _ = client.ForEachNode(func(node *redis.Client) error { + _ = client.ForEachNode(ctx, func(ctx context.Context, node *redis.Client) error { node.AddHook(nodeHook) return nil }) - err = client.Ping().Err() + err = client.Ping(ctx).Err() Expect(err).NotTo(HaveOccurred()) Expect(stack).To(Equal([]string{ "cluster.BeforeProcess", @@ -587,11 +589,11 @@ var _ = Describe("ClusterClient", func() { }) It("supports Pipeline hook", func() { - err := client.Ping().Err() + err := client.Ping(ctx).Err() Expect(err).NotTo(HaveOccurred()) - err = client.ForEachNode(func(node *redis.Client) error { - return node.Ping().Err() + err = client.ForEachNode(ctx, func(ctx context.Context, node *redis.Client) error { + return node.Ping(ctx).Err() }) Expect(err).NotTo(HaveOccurred()) @@ -612,7 +614,7 @@ var _ = Describe("ClusterClient", func() { }, }) - _ = client.ForEachNode(func(node *redis.Client) error { + _ = client.ForEachNode(ctx, func(ctx context.Context, node *redis.Client) error { node.AddHook(&hook{ beforeProcessPipeline: func(ctx context.Context, cmds []redis.Cmder) (context.Context, error) { Expect(cmds).To(HaveLen(1)) @@ -630,8 +632,8 @@ var _ = Describe("ClusterClient", func() { return nil }) - _, err = client.Pipelined(func(pipe redis.Pipeliner) error { - pipe.Ping() + _, err = client.Pipelined(ctx, func(pipe redis.Pipeliner) error { + pipe.Ping(ctx) return nil }) Expect(err).NotTo(HaveOccurred()) @@ -644,11 +646,11 @@ var _ = Describe("ClusterClient", func() { }) It("supports TxPipeline hook", func() { - err := client.Ping().Err() + err := client.Ping(ctx).Err() Expect(err).NotTo(HaveOccurred()) - err = client.ForEachNode(func(node *redis.Client) error { - return node.Ping().Err() + err = client.ForEachNode(ctx, func(ctx context.Context, node *redis.Client) error { + return node.Ping(ctx).Err() }) Expect(err).NotTo(HaveOccurred()) @@ -669,7 +671,7 @@ var _ = Describe("ClusterClient", func() { }, }) - _ = client.ForEachNode(func(node *redis.Client) error { + _ = client.ForEachNode(ctx, func(ctx context.Context, node *redis.Client) error { node.AddHook(&hook{ beforeProcessPipeline: func(ctx context.Context, cmds []redis.Cmder) (context.Context, error) { Expect(cmds).To(HaveLen(3)) @@ -687,8 +689,8 @@ var _ = Describe("ClusterClient", func() { return nil }) - _, err = client.TxPipelined(func(pipe redis.Pipeliner) error { - pipe.Ping() + _, err = client.TxPipelined(ctx, func(pipe redis.Pipeliner) error { + pipe.Ping(ctx) return nil }) Expect(err).NotTo(HaveOccurred()) @@ -704,17 +706,17 @@ var _ = Describe("ClusterClient", func() { Describe("ClusterClient", func() { BeforeEach(func() { opt = redisClusterOptions() - client = cluster.newClusterClient(opt) + client = cluster.newClusterClient(ctx, opt) - err := client.ForEachMaster(func(master *redis.Client) error { - return master.FlushDB().Err() + err := client.ForEachMaster(ctx, func(ctx context.Context, master *redis.Client) error { + return master.FlushDB(ctx).Err() }) Expect(err).NotTo(HaveOccurred()) }) AfterEach(func() { - _ = client.ForEachMaster(func(master *redis.Client) error { - return master.FlushDB().Err() + _ = client.ForEachMaster(ctx, func(ctx context.Context, master *redis.Client) error { + return master.FlushDB(ctx).Err() }) Expect(client.Close()).NotTo(HaveOccurred()) }) @@ -727,13 +729,13 @@ var _ = Describe("ClusterClient", func() { It("returns an error when there are no attempts left", func() { opt := redisClusterOptions() opt.MaxRedirects = -1 - client := cluster.newClusterClient(opt) + client := cluster.newClusterClient(ctx, opt) Eventually(func() error { - return client.SwapNodes("A") + return client.SwapNodes(ctx, "A") }, 30*time.Second).ShouldNot(HaveOccurred()) - err := client.Get("A").Err() + err := client.Get(ctx, "A").Err() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("MOVED")) @@ -742,21 +744,21 @@ var _ = Describe("ClusterClient", func() { It("calls fn for every master node", func() { for i := 0; i < 10; i++ { - Expect(client.Set(strconv.Itoa(i), "", 0).Err()).NotTo(HaveOccurred()) + Expect(client.Set(ctx, strconv.Itoa(i), "", 0).Err()).NotTo(HaveOccurred()) } - err := client.ForEachMaster(func(master *redis.Client) error { - return master.FlushDB().Err() + err := client.ForEachMaster(ctx, func(ctx context.Context, master *redis.Client) error { + return master.FlushDB(ctx).Err() }) Expect(err).NotTo(HaveOccurred()) - size, err := client.DBSize().Result() + size, err := client.DBSize(ctx).Result() Expect(err).NotTo(HaveOccurred()) Expect(size).To(Equal(int64(0))) }) It("should CLUSTER SLOTS", func() { - res, err := client.ClusterSlots().Result() + res, err := client.ClusterSlots(ctx).Result() Expect(err).NotTo(HaveOccurred()) Expect(res).To(HaveLen(3)) @@ -795,49 +797,49 @@ var _ = Describe("ClusterClient", func() { }) It("should CLUSTER NODES", func() { - res, err := client.ClusterNodes().Result() + res, err := client.ClusterNodes(ctx).Result() Expect(err).NotTo(HaveOccurred()) Expect(len(res)).To(BeNumerically(">", 400)) }) It("should CLUSTER INFO", func() { - res, err := client.ClusterInfo().Result() + res, err := client.ClusterInfo(ctx).Result() Expect(err).NotTo(HaveOccurred()) Expect(res).To(ContainSubstring("cluster_known_nodes:6")) }) It("should CLUSTER KEYSLOT", func() { - hashSlot, err := client.ClusterKeySlot("somekey").Result() + hashSlot, err := client.ClusterKeySlot(ctx, "somekey").Result() Expect(err).NotTo(HaveOccurred()) Expect(hashSlot).To(Equal(int64(hashtag.Slot("somekey")))) }) It("should CLUSTER GETKEYSINSLOT", func() { - keys, err := client.ClusterGetKeysInSlot(hashtag.Slot("somekey"), 1).Result() + keys, err := client.ClusterGetKeysInSlot(ctx, hashtag.Slot("somekey"), 1).Result() Expect(err).NotTo(HaveOccurred()) Expect(len(keys)).To(Equal(0)) }) It("should CLUSTER COUNT-FAILURE-REPORTS", func() { - n, err := client.ClusterCountFailureReports(cluster.nodeIDs[0]).Result() + n, err := client.ClusterCountFailureReports(ctx, cluster.nodeIDs[0]).Result() Expect(err).NotTo(HaveOccurred()) Expect(n).To(Equal(int64(0))) }) It("should CLUSTER COUNTKEYSINSLOT", func() { - n, err := client.ClusterCountKeysInSlot(10).Result() + n, err := client.ClusterCountKeysInSlot(ctx, 10).Result() Expect(err).NotTo(HaveOccurred()) Expect(n).To(Equal(int64(0))) }) It("should CLUSTER SAVECONFIG", func() { - res, err := client.ClusterSaveConfig().Result() + res, err := client.ClusterSaveConfig(ctx).Result() Expect(err).NotTo(HaveOccurred()) Expect(res).To(Equal("OK")) }) It("should CLUSTER SLAVES", func() { - nodesList, err := client.ClusterSlaves(cluster.nodeIDs[0]).Result() + nodesList, err := client.ClusterSlaves(ctx, cluster.nodeIDs[0]).Result() Expect(err).NotTo(HaveOccurred()) Expect(nodesList).Should(ContainElement(ContainSubstring("slave"))) Expect(nodesList).Should(HaveLen(1)) @@ -847,7 +849,7 @@ var _ = Describe("ClusterClient", func() { const nkeys = 100 for i := 0; i < nkeys; i++ { - err := client.Set(fmt.Sprintf("key%d", i), "value", 0).Err() + err := client.Set(ctx, fmt.Sprintf("key%d", i), "value", 0).Err() Expect(err).NotTo(HaveOccurred()) } @@ -862,7 +864,7 @@ var _ = Describe("ClusterClient", func() { } for i := 0; i < nkeys*10; i++ { - key := client.RandomKey().Val() + key := client.RandomKey(ctx).Val() addKey(key) } @@ -879,40 +881,40 @@ var _ = Describe("ClusterClient", func() { opt = redisClusterOptions() opt.MinRetryBackoff = 250 * time.Millisecond opt.MaxRetryBackoff = time.Second - client = cluster.newClusterClient(opt) + client = cluster.newClusterClient(ctx, opt) - err := client.ForEachMaster(func(master *redis.Client) error { - return master.FlushDB().Err() + err := client.ForEachMaster(ctx, func(ctx context.Context, master *redis.Client) error { + return master.FlushDB(ctx).Err() }) Expect(err).NotTo(HaveOccurred()) - err = client.ForEachSlave(func(slave *redis.Client) error { + err = client.ForEachSlave(ctx, func(ctx context.Context, slave *redis.Client) error { defer GinkgoRecover() Eventually(func() int64 { - return slave.DBSize().Val() + return slave.DBSize(ctx).Val() }, "30s").Should(Equal(int64(0))) return nil }) Expect(err).NotTo(HaveOccurred()) - state, err := client.LoadState() + state, err := client.LoadState(ctx) Eventually(func() bool { - state, err = client.LoadState() + state, err = client.LoadState(ctx) if err != nil { return false } - return state.IsConsistent() + return state.IsConsistent(ctx) }, "30s").Should(BeTrue()) for _, slave := range state.Slaves { - err = slave.Client.ClusterFailover().Err() + err = slave.Client.ClusterFailover(ctx).Err() Expect(err).NotTo(HaveOccurred()) Eventually(func() bool { - state, _ := client.LoadState() - return state.IsConsistent() + state, _ := client.LoadState(ctx) + return state.IsConsistent(ctx) }, "30s").Should(BeTrue()) } }) @@ -929,16 +931,16 @@ var _ = Describe("ClusterClient", func() { BeforeEach(func() { opt = redisClusterOptions() opt.RouteByLatency = true - client = cluster.newClusterClient(opt) + client = cluster.newClusterClient(ctx, opt) - err := client.ForEachMaster(func(master *redis.Client) error { - return master.FlushDB().Err() + err := client.ForEachMaster(ctx, func(ctx context.Context, master *redis.Client) error { + return master.FlushDB(ctx).Err() }) Expect(err).NotTo(HaveOccurred()) - err = client.ForEachSlave(func(slave *redis.Client) error { + err = client.ForEachSlave(ctx, func(ctx context.Context, slave *redis.Client) error { Eventually(func() int64 { - return client.DBSize().Val() + return client.DBSize(ctx).Val() }, 30*time.Second).Should(Equal(int64(0))) return nil }) @@ -946,8 +948,8 @@ var _ = Describe("ClusterClient", func() { }) AfterEach(func() { - err := client.ForEachSlave(func(slave *redis.Client) error { - return slave.ReadWrite().Err() + err := client.ForEachSlave(ctx, func(ctx context.Context, slave *redis.Client) error { + return slave.ReadWrite(ctx).Err() }) Expect(err).NotTo(HaveOccurred()) @@ -985,16 +987,16 @@ var _ = Describe("ClusterClient", func() { }} return slots, nil } - client = cluster.newClusterClient(opt) + client = cluster.newClusterClient(ctx, opt) - err := client.ForEachMaster(func(master *redis.Client) error { - return master.FlushDB().Err() + err := client.ForEachMaster(ctx, func(ctx context.Context, master *redis.Client) error { + return master.FlushDB(ctx).Err() }) Expect(err).NotTo(HaveOccurred()) - err = client.ForEachSlave(func(slave *redis.Client) error { + err = client.ForEachSlave(ctx, func(ctx context.Context, slave *redis.Client) error { Eventually(func() int64 { - return client.DBSize().Val() + return client.DBSize(ctx).Val() }, 30*time.Second).Should(Equal(int64(0))) return nil }) @@ -1039,16 +1041,16 @@ var _ = Describe("ClusterClient", func() { }} return slots, nil } - client = cluster.newClusterClient(opt) + client = cluster.newClusterClient(ctx, opt) - err := client.ForEachMaster(func(master *redis.Client) error { - return master.FlushDB().Err() + err := client.ForEachMaster(ctx, func(ctx context.Context, master *redis.Client) error { + return master.FlushDB(ctx).Err() }) Expect(err).NotTo(HaveOccurred()) - err = client.ForEachSlave(func(slave *redis.Client) error { + err = client.ForEachSlave(ctx, func(ctx context.Context, slave *redis.Client) error { Eventually(func() int64 { - return client.DBSize().Val() + return client.DBSize(ctx).Val() }, 30*time.Second).Should(Equal(int64(0))) return nil }) @@ -1078,13 +1080,13 @@ var _ = Describe("ClusterClient without nodes", func() { }) It("Ping returns an error", func() { - err := client.Ping().Err() + err := client.Ping(ctx).Err() Expect(err).To(MatchError("redis: cluster has no nodes")) }) It("pipeline returns an error", func() { - _, err := client.Pipelined(func(pipe redis.Pipeliner) error { - pipe.Ping() + _, err := client.Pipelined(ctx, func(pipe redis.Pipeliner) error { + pipe.Ping(ctx) return nil }) Expect(err).To(MatchError("redis: cluster has no nodes")) @@ -1105,13 +1107,13 @@ var _ = Describe("ClusterClient without valid nodes", func() { }) It("returns an error", func() { - err := client.Ping().Err() + err := client.Ping(ctx).Err() Expect(err).To(MatchError("ERR This instance has cluster support disabled")) }) It("pipeline returns an error", func() { - _, err := client.Pipelined(func(pipe redis.Pipeliner) error { - pipe.Ping() + _, err := client.Pipelined(ctx, func(pipe redis.Pipeliner) error { + pipe.Ping(ctx) return nil }) Expect(err).To(MatchError("ERR This instance has cluster support disabled")) @@ -1123,7 +1125,7 @@ var _ = Describe("ClusterClient with unavailable Cluster", func() { BeforeEach(func() { for _, node := range cluster.clients { - err := node.ClientPause(5 * time.Second).Err() + err := node.ClientPause(ctx, 5*time.Second).Err() Expect(err).NotTo(HaveOccurred()) } @@ -1139,11 +1141,11 @@ var _ = Describe("ClusterClient with unavailable Cluster", func() { }) It("recovers when Cluster recovers", func() { - err := client.Ping().Err() + err := client.Ping(ctx).Err() Expect(err).To(HaveOccurred()) Eventually(func() error { - return client.Ping().Err() + return client.Ping(ctx).Err() }, "30s").ShouldNot(HaveOccurred()) }) }) @@ -1157,14 +1159,14 @@ var _ = Describe("ClusterClient timeout", func() { testTimeout := func() { It("Ping timeouts", func() { - err := client.Ping().Err() + err := client.Ping(ctx).Err() Expect(err).To(HaveOccurred()) Expect(err.(net.Error).Timeout()).To(BeTrue()) }) It("Pipeline timeouts", func() { - _, err := client.Pipelined(func(pipe redis.Pipeliner) error { - pipe.Ping() + _, err := client.Pipelined(ctx, func(pipe redis.Pipeliner) error { + pipe.Ping(ctx) return nil }) Expect(err).To(HaveOccurred()) @@ -1172,17 +1174,17 @@ var _ = Describe("ClusterClient timeout", func() { }) It("Tx timeouts", func() { - err := client.Watch(func(tx *redis.Tx) error { - return tx.Ping().Err() + err := client.Watch(ctx, func(tx *redis.Tx) error { + return tx.Ping(ctx).Err() }, "foo") Expect(err).To(HaveOccurred()) Expect(err.(net.Error).Timeout()).To(BeTrue()) }) It("Tx Pipeline timeouts", func() { - err := client.Watch(func(tx *redis.Tx) error { - _, err := tx.TxPipelined(func(pipe redis.Pipeliner) error { - pipe.Ping() + err := client.Watch(ctx, func(tx *redis.Tx) error { + _, err := tx.TxPipelined(ctx, func(pipe redis.Pipeliner) error { + pipe.Ping(ctx) return nil }) return err @@ -1200,19 +1202,19 @@ var _ = Describe("ClusterClient timeout", func() { opt.ReadTimeout = 250 * time.Millisecond opt.WriteTimeout = 250 * time.Millisecond opt.MaxRedirects = 1 - client = cluster.newClusterClient(opt) + client = cluster.newClusterClient(ctx, opt) - err := client.ForEachNode(func(client *redis.Client) error { - return client.ClientPause(pause).Err() + err := client.ForEachNode(ctx, func(ctx context.Context, client *redis.Client) error { + return client.ClientPause(ctx, pause).Err() }) Expect(err).NotTo(HaveOccurred()) }) AfterEach(func() { - _ = client.ForEachNode(func(client *redis.Client) error { + _ = client.ForEachNode(ctx, func(ctx context.Context, client *redis.Client) error { defer GinkgoRecover() Eventually(func() error { - return client.Ping().Err() + return client.Ping(ctx).Err() }, 2*pause).ShouldNot(HaveOccurred()) return nil }) diff --git a/command.go b/command.go index 266e389..f0a6133 100644 --- a/command.go +++ b/command.go @@ -1,6 +1,7 @@ package redis import ( + "context" "fmt" "net" "strconv" @@ -95,6 +96,7 @@ func cmdFirstKeyPos(cmd Cmder, info *CommandInfo) int { //------------------------------------------------------------------------------ type baseCmd struct { + ctx context.Context args []interface{} err error @@ -147,9 +149,12 @@ type Cmd struct { val interface{} } -func NewCmd(args ...interface{}) *Cmd { +func NewCmd(ctx context.Context, args ...interface{}) *Cmd { return &Cmd{ - baseCmd: baseCmd{args: args}, + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, } } @@ -308,9 +313,12 @@ type SliceCmd struct { var _ Cmder = (*SliceCmd)(nil) -func NewSliceCmd(args ...interface{}) *SliceCmd { +func NewSliceCmd(ctx context.Context, args ...interface{}) *SliceCmd { return &SliceCmd{ - baseCmd: baseCmd{args: args}, + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, } } @@ -346,9 +354,12 @@ type StatusCmd struct { var _ Cmder = (*StatusCmd)(nil) -func NewStatusCmd(args ...interface{}) *StatusCmd { +func NewStatusCmd(ctx context.Context, args ...interface{}) *StatusCmd { return &StatusCmd{ - baseCmd: baseCmd{args: args}, + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, } } @@ -379,9 +390,12 @@ type IntCmd struct { var _ Cmder = (*IntCmd)(nil) -func NewIntCmd(args ...interface{}) *IntCmd { +func NewIntCmd(ctx context.Context, args ...interface{}) *IntCmd { return &IntCmd{ - baseCmd: baseCmd{args: args}, + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, } } @@ -416,9 +430,12 @@ type IntSliceCmd struct { var _ Cmder = (*IntSliceCmd)(nil) -func NewIntSliceCmd(args ...interface{}) *IntSliceCmd { +func NewIntSliceCmd(ctx context.Context, args ...interface{}) *IntSliceCmd { return &IntSliceCmd{ - baseCmd: baseCmd{args: args}, + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, } } @@ -460,9 +477,12 @@ type DurationCmd struct { var _ Cmder = (*DurationCmd)(nil) -func NewDurationCmd(precision time.Duration, args ...interface{}) *DurationCmd { +func NewDurationCmd(ctx context.Context, precision time.Duration, args ...interface{}) *DurationCmd { return &DurationCmd{ - baseCmd: baseCmd{args: args}, + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, precision: precision, } } @@ -506,9 +526,12 @@ type TimeCmd struct { var _ Cmder = (*TimeCmd)(nil) -func NewTimeCmd(args ...interface{}) *TimeCmd { +func NewTimeCmd(ctx context.Context, args ...interface{}) *TimeCmd { return &TimeCmd{ - baseCmd: baseCmd{args: args}, + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, } } @@ -556,9 +579,12 @@ type BoolCmd struct { var _ Cmder = (*BoolCmd)(nil) -func NewBoolCmd(args ...interface{}) *BoolCmd { +func NewBoolCmd(ctx context.Context, args ...interface{}) *BoolCmd { return &BoolCmd{ - baseCmd: baseCmd{args: args}, + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, } } @@ -610,9 +636,12 @@ type StringCmd struct { var _ Cmder = (*StringCmd)(nil) -func NewStringCmd(args ...interface{}) *StringCmd { +func NewStringCmd(ctx context.Context, args ...interface{}) *StringCmd { return &StringCmd{ - baseCmd: baseCmd{args: args}, + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, } } @@ -700,9 +729,12 @@ type FloatCmd struct { var _ Cmder = (*FloatCmd)(nil) -func NewFloatCmd(args ...interface{}) *FloatCmd { +func NewFloatCmd(ctx context.Context, args ...interface{}) *FloatCmd { return &FloatCmd{ - baseCmd: baseCmd{args: args}, + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, } } @@ -733,9 +765,12 @@ type StringSliceCmd struct { var _ Cmder = (*StringSliceCmd)(nil) -func NewStringSliceCmd(args ...interface{}) *StringSliceCmd { +func NewStringSliceCmd(ctx context.Context, args ...interface{}) *StringSliceCmd { return &StringSliceCmd{ - baseCmd: baseCmd{args: args}, + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, } } @@ -783,9 +818,12 @@ type BoolSliceCmd struct { var _ Cmder = (*BoolSliceCmd)(nil) -func NewBoolSliceCmd(args ...interface{}) *BoolSliceCmd { +func NewBoolSliceCmd(ctx context.Context, args ...interface{}) *BoolSliceCmd { return &BoolSliceCmd{ - baseCmd: baseCmd{args: args}, + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, } } @@ -826,9 +864,12 @@ type StringStringMapCmd struct { var _ Cmder = (*StringStringMapCmd)(nil) -func NewStringStringMapCmd(args ...interface{}) *StringStringMapCmd { +func NewStringStringMapCmd(ctx context.Context, args ...interface{}) *StringStringMapCmd { return &StringStringMapCmd{ - baseCmd: baseCmd{args: args}, + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, } } @@ -875,9 +916,12 @@ type StringIntMapCmd struct { var _ Cmder = (*StringIntMapCmd)(nil) -func NewStringIntMapCmd(args ...interface{}) *StringIntMapCmd { +func NewStringIntMapCmd(ctx context.Context, args ...interface{}) *StringIntMapCmd { return &StringIntMapCmd{ - baseCmd: baseCmd{args: args}, + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, } } @@ -924,9 +968,12 @@ type StringStructMapCmd struct { var _ Cmder = (*StringStructMapCmd)(nil) -func NewStringStructMapCmd(args ...interface{}) *StringStructMapCmd { +func NewStringStructMapCmd(ctx context.Context, args ...interface{}) *StringStructMapCmd { return &StringStructMapCmd{ - baseCmd: baseCmd{args: args}, + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, } } @@ -972,9 +1019,12 @@ type XMessageSliceCmd struct { var _ Cmder = (*XMessageSliceCmd)(nil) -func NewXMessageSliceCmd(args ...interface{}) *XMessageSliceCmd { +func NewXMessageSliceCmd(ctx context.Context, args ...interface{}) *XMessageSliceCmd { return &XMessageSliceCmd{ - baseCmd: baseCmd{args: args}, + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, } } @@ -1069,9 +1119,12 @@ type XStreamSliceCmd struct { var _ Cmder = (*XStreamSliceCmd)(nil) -func NewXStreamSliceCmd(args ...interface{}) *XStreamSliceCmd { +func NewXStreamSliceCmd(ctx context.Context, args ...interface{}) *XStreamSliceCmd { return &XStreamSliceCmd{ - baseCmd: baseCmd{args: args}, + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, } } @@ -1138,9 +1191,12 @@ type XPendingCmd struct { var _ Cmder = (*XPendingCmd)(nil) -func NewXPendingCmd(args ...interface{}) *XPendingCmd { +func NewXPendingCmd(ctx context.Context, args ...interface{}) *XPendingCmd { return &XPendingCmd{ - baseCmd: baseCmd{args: args}, + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, } } @@ -1237,9 +1293,12 @@ type XPendingExtCmd struct { var _ Cmder = (*XPendingExtCmd)(nil) -func NewXPendingExtCmd(args ...interface{}) *XPendingExtCmd { +func NewXPendingExtCmd(ctx context.Context, args ...interface{}) *XPendingExtCmd { return &XPendingExtCmd{ - baseCmd: baseCmd{args: args}, + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, } } @@ -1317,9 +1376,12 @@ type XInfoGroups struct { var _ Cmder = (*XInfoGroupsCmd)(nil) -func NewXInfoGroupsCmd(stream string) *XInfoGroupsCmd { +func NewXInfoGroupsCmd(ctx context.Context, stream string) *XInfoGroupsCmd { return &XInfoGroupsCmd{ - baseCmd: baseCmd{args: []interface{}{"xinfo", "groups", stream}}, + baseCmd: baseCmd{ + ctx: ctx, + args: []interface{}{"xinfo", "groups", stream}, + }, } } @@ -1401,9 +1463,12 @@ type ZSliceCmd struct { var _ Cmder = (*ZSliceCmd)(nil) -func NewZSliceCmd(args ...interface{}) *ZSliceCmd { +func NewZSliceCmd(ctx context.Context, args ...interface{}) *ZSliceCmd { return &ZSliceCmd{ - baseCmd: baseCmd{args: args}, + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, } } @@ -1453,9 +1518,12 @@ type ZWithKeyCmd struct { var _ Cmder = (*ZWithKeyCmd)(nil) -func NewZWithKeyCmd(args ...interface{}) *ZWithKeyCmd { +func NewZWithKeyCmd(ctx context.Context, args ...interface{}) *ZWithKeyCmd { return &ZWithKeyCmd{ - baseCmd: baseCmd{args: args}, + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, } } @@ -1508,14 +1576,17 @@ type ScanCmd struct { page []string cursor uint64 - process func(cmd Cmder) error + process cmdable } var _ Cmder = (*ScanCmd)(nil) -func NewScanCmd(process func(cmd Cmder) error, args ...interface{}) *ScanCmd { +func NewScanCmd(ctx context.Context, process cmdable, args ...interface{}) *ScanCmd { return &ScanCmd{ - baseCmd: baseCmd{args: args}, + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, process: process, } } @@ -1565,9 +1636,12 @@ type ClusterSlotsCmd struct { var _ Cmder = (*ClusterSlotsCmd)(nil) -func NewClusterSlotsCmd(args ...interface{}) *ClusterSlotsCmd { +func NewClusterSlotsCmd(ctx context.Context, args ...interface{}) *ClusterSlotsCmd { return &ClusterSlotsCmd{ - baseCmd: baseCmd{args: args}, + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, } } @@ -1682,10 +1756,13 @@ type GeoLocationCmd struct { var _ Cmder = (*GeoLocationCmd)(nil) -func NewGeoLocationCmd(q *GeoRadiusQuery, args ...interface{}) *GeoLocationCmd { +func NewGeoLocationCmd(ctx context.Context, q *GeoRadiusQuery, args ...interface{}) *GeoLocationCmd { return &GeoLocationCmd{ - baseCmd: baseCmd{args: geoLocationArgs(q, args...)}, - q: q, + baseCmd: baseCmd{ + ctx: ctx, + args: geoLocationArgs(q, args...), + }, + q: q, } } @@ -1826,9 +1903,12 @@ type GeoPosCmd struct { var _ Cmder = (*GeoPosCmd)(nil) -func NewGeoPosCmd(args ...interface{}) *GeoPosCmd { +func NewGeoPosCmd(ctx context.Context, args ...interface{}) *GeoPosCmd { return &GeoPosCmd{ - baseCmd: baseCmd{args: args}, + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, } } @@ -1899,9 +1979,12 @@ type CommandsInfoCmd struct { var _ Cmder = (*CommandsInfoCmd)(nil) -func NewCommandsInfoCmd(args ...interface{}) *CommandsInfoCmd { +func NewCommandsInfoCmd(ctx context.Context, args ...interface{}) *CommandsInfoCmd { return &CommandsInfoCmd{ - baseCmd: baseCmd{args: args}, + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, } } diff --git a/command_test.go b/command_test.go index e9fc958..ed506a4 100644 --- a/command_test.go +++ b/command_test.go @@ -15,7 +15,7 @@ var _ = Describe("Cmd", func() { BeforeEach(func() { client = redis.NewClient(redisOptions()) - Expect(client.FlushDB().Err()).NotTo(HaveOccurred()) + Expect(client.FlushDB(ctx).Err()).NotTo(HaveOccurred()) }) AfterEach(func() { @@ -23,19 +23,19 @@ var _ = Describe("Cmd", func() { }) It("implements Stringer", func() { - set := client.Set("foo", "bar", 0) + set := client.Set(ctx, "foo", "bar", 0) Expect(set.String()).To(Equal("set foo bar: OK")) - get := client.Get("foo") + get := client.Get(ctx, "foo") Expect(get.String()).To(Equal("get foo: bar")) }) It("has val/err", func() { - set := client.Set("key", "hello", 0) + set := client.Set(ctx, "key", "hello", 0) Expect(set.Err()).NotTo(HaveOccurred()) Expect(set.Val()).To(Equal("OK")) - get := client.Get("key") + get := client.Get(ctx, "key") Expect(get.Err()).NotTo(HaveOccurred()) Expect(get.Val()).To(Equal("hello")) @@ -44,18 +44,18 @@ var _ = Describe("Cmd", func() { }) It("has helpers", func() { - set := client.Set("key", "10", 0) + set := client.Set(ctx, "key", "10", 0) Expect(set.Err()).NotTo(HaveOccurred()) - n, err := client.Get("key").Int64() + n, err := client.Get(ctx, "key").Int64() Expect(err).NotTo(HaveOccurred()) Expect(n).To(Equal(int64(10))) - un, err := client.Get("key").Uint64() + un, err := client.Get(ctx, "key").Uint64() Expect(err).NotTo(HaveOccurred()) Expect(un).To(Equal(uint64(10))) - f, err := client.Get("key").Float64() + f, err := client.Get(ctx, "key").Float64() Expect(err).NotTo(HaveOccurred()) Expect(f).To(Equal(float64(10))) }) @@ -63,10 +63,10 @@ var _ = Describe("Cmd", func() { It("supports float32", func() { f := float32(66.97) - err := client.Set("float_key", f, 0).Err() + err := client.Set(ctx, "float_key", f, 0).Err() Expect(err).NotTo(HaveOccurred()) - val, err := client.Get("float_key").Float32() + val, err := client.Get(ctx, "float_key").Float32() Expect(err).NotTo(HaveOccurred()) Expect(val).To(Equal(f)) }) @@ -74,14 +74,14 @@ var _ = Describe("Cmd", func() { It("supports time.Time", func() { tm := time.Date(2019, 01, 01, 0, 0, 0, 0, time.UTC) - err := client.Set("time_key", tm, 0).Err() + err := client.Set(ctx, "time_key", tm, 0).Err() Expect(err).NotTo(HaveOccurred()) - s, err := client.Get("time_key").Result() + s, err := client.Get(ctx, "time_key").Result() Expect(err).NotTo(HaveOccurred()) Expect(s).To(Equal("2019-01-01T00:00:00Z")) - tm2, err := client.Get("time_key").Time() + tm2, err := client.Get(ctx, "time_key").Time() Expect(err).NotTo(HaveOccurred()) Expect(tm2).To(BeTemporally("==", tm)) }) diff --git a/commands.go b/commands.go index d4447c4..073b7fc 100644 --- a/commands.go +++ b/commands.go @@ -1,6 +1,7 @@ package redis import ( + "context" "errors" "io" "time" @@ -54,257 +55,270 @@ func appendArgs(dst, src []interface{}) []interface{} { type Cmdable interface { Pipeline() Pipeliner - Pipelined(fn func(Pipeliner) error) ([]Cmder, error) + Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) - TxPipelined(fn func(Pipeliner) error) ([]Cmder, error) + TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) TxPipeline() Pipeliner - Command() *CommandsInfoCmd - ClientGetName() *StringCmd - Echo(message interface{}) *StringCmd - Ping() *StatusCmd - Quit() *StatusCmd - Del(keys ...string) *IntCmd - Unlink(keys ...string) *IntCmd - Dump(key string) *StringCmd - Exists(keys ...string) *IntCmd - Expire(key string, expiration time.Duration) *BoolCmd - ExpireAt(key string, tm time.Time) *BoolCmd - Keys(pattern string) *StringSliceCmd - Migrate(host, port, key string, db int, timeout time.Duration) *StatusCmd - Move(key string, db int) *BoolCmd - ObjectRefCount(key string) *IntCmd - ObjectEncoding(key string) *StringCmd - ObjectIdleTime(key string) *DurationCmd - Persist(key string) *BoolCmd - PExpire(key string, expiration time.Duration) *BoolCmd - PExpireAt(key string, tm time.Time) *BoolCmd - PTTL(key string) *DurationCmd - RandomKey() *StringCmd - Rename(key, newkey string) *StatusCmd - RenameNX(key, newkey string) *BoolCmd - Restore(key string, ttl time.Duration, value string) *StatusCmd - RestoreReplace(key string, ttl time.Duration, value string) *StatusCmd - Sort(key string, sort *Sort) *StringSliceCmd - SortStore(key, store string, sort *Sort) *IntCmd - SortInterfaces(key string, sort *Sort) *SliceCmd - Touch(keys ...string) *IntCmd - TTL(key string) *DurationCmd - Type(key string) *StatusCmd - Scan(cursor uint64, match string, count int64) *ScanCmd - SScan(key string, cursor uint64, match string, count int64) *ScanCmd - HScan(key string, cursor uint64, match string, count int64) *ScanCmd - ZScan(key string, cursor uint64, match string, count int64) *ScanCmd - Append(key, value string) *IntCmd - BitCount(key string, bitCount *BitCount) *IntCmd - BitOpAnd(destKey string, keys ...string) *IntCmd - BitOpOr(destKey string, keys ...string) *IntCmd - BitOpXor(destKey string, keys ...string) *IntCmd - BitOpNot(destKey string, key string) *IntCmd - BitPos(key string, bit int64, pos ...int64) *IntCmd - BitField(key string, args ...interface{}) *IntSliceCmd - Decr(key string) *IntCmd - DecrBy(key string, decrement int64) *IntCmd - Get(key string) *StringCmd - GetBit(key string, offset int64) *IntCmd - GetRange(key string, start, end int64) *StringCmd - GetSet(key string, value interface{}) *StringCmd - Incr(key string) *IntCmd - IncrBy(key string, value int64) *IntCmd - IncrByFloat(key string, value float64) *FloatCmd - MGet(keys ...string) *SliceCmd - MSet(values ...interface{}) *StatusCmd - MSetNX(values ...interface{}) *BoolCmd - Set(key string, value interface{}, expiration time.Duration) *StatusCmd - SetBit(key string, offset int64, value int) *IntCmd - SetNX(key string, value interface{}, expiration time.Duration) *BoolCmd - SetXX(key string, value interface{}, expiration time.Duration) *BoolCmd - SetRange(key string, offset int64, value string) *IntCmd - StrLen(key string) *IntCmd - HDel(key string, fields ...string) *IntCmd - HExists(key, field string) *BoolCmd - HGet(key, field string) *StringCmd - HGetAll(key string) *StringStringMapCmd - HIncrBy(key, field string, incr int64) *IntCmd - HIncrByFloat(key, field string, incr float64) *FloatCmd - HKeys(key string) *StringSliceCmd - HLen(key string) *IntCmd - HMGet(key string, fields ...string) *SliceCmd - HSet(key string, values ...interface{}) *IntCmd - HMSet(key string, values ...interface{}) *BoolCmd - HSetNX(key, field string, value interface{}) *BoolCmd - HVals(key string) *StringSliceCmd - BLPop(timeout time.Duration, keys ...string) *StringSliceCmd - BRPop(timeout time.Duration, keys ...string) *StringSliceCmd - BRPopLPush(source, destination string, timeout time.Duration) *StringCmd - LIndex(key string, index int64) *StringCmd - LInsert(key, op string, pivot, value interface{}) *IntCmd - LInsertBefore(key string, pivot, value interface{}) *IntCmd - LInsertAfter(key string, pivot, value interface{}) *IntCmd - LLen(key string) *IntCmd - LPop(key string) *StringCmd - LPush(key string, values ...interface{}) *IntCmd - LPushX(key string, values ...interface{}) *IntCmd - LRange(key string, start, stop int64) *StringSliceCmd - LRem(key string, count int64, value interface{}) *IntCmd - LSet(key string, index int64, value interface{}) *StatusCmd - LTrim(key string, start, stop int64) *StatusCmd - RPop(key string) *StringCmd - RPopLPush(source, destination string) *StringCmd - RPush(key string, values ...interface{}) *IntCmd - RPushX(key string, values ...interface{}) *IntCmd - SAdd(key string, members ...interface{}) *IntCmd - SCard(key string) *IntCmd - SDiff(keys ...string) *StringSliceCmd - SDiffStore(destination string, keys ...string) *IntCmd - SInter(keys ...string) *StringSliceCmd - SInterStore(destination string, keys ...string) *IntCmd - SIsMember(key string, member interface{}) *BoolCmd - SMembers(key string) *StringSliceCmd - SMembersMap(key string) *StringStructMapCmd - SMove(source, destination string, member interface{}) *BoolCmd - SPop(key string) *StringCmd - SPopN(key string, count int64) *StringSliceCmd - SRandMember(key string) *StringCmd - SRandMemberN(key string, count int64) *StringSliceCmd - SRem(key string, members ...interface{}) *IntCmd - SUnion(keys ...string) *StringSliceCmd - SUnionStore(destination string, keys ...string) *IntCmd - XAdd(a *XAddArgs) *StringCmd - XDel(stream string, ids ...string) *IntCmd - XLen(stream string) *IntCmd - XRange(stream, start, stop string) *XMessageSliceCmd - XRangeN(stream, start, stop string, count int64) *XMessageSliceCmd - XRevRange(stream string, start, stop string) *XMessageSliceCmd - XRevRangeN(stream string, start, stop string, count int64) *XMessageSliceCmd - XRead(a *XReadArgs) *XStreamSliceCmd - XReadStreams(streams ...string) *XStreamSliceCmd - XGroupCreate(stream, group, start string) *StatusCmd - XGroupCreateMkStream(stream, group, start string) *StatusCmd - XGroupSetID(stream, group, start string) *StatusCmd - XGroupDestroy(stream, group string) *IntCmd - XGroupDelConsumer(stream, group, consumer string) *IntCmd - XReadGroup(a *XReadGroupArgs) *XStreamSliceCmd - XAck(stream, group string, ids ...string) *IntCmd - XPending(stream, group string) *XPendingCmd - XPendingExt(a *XPendingExtArgs) *XPendingExtCmd - XClaim(a *XClaimArgs) *XMessageSliceCmd - XClaimJustID(a *XClaimArgs) *StringSliceCmd - XTrim(key string, maxLen int64) *IntCmd - XTrimApprox(key string, maxLen int64) *IntCmd - XInfoGroups(key string) *XInfoGroupsCmd - BZPopMax(timeout time.Duration, keys ...string) *ZWithKeyCmd - BZPopMin(timeout time.Duration, keys ...string) *ZWithKeyCmd - ZAdd(key string, members ...*Z) *IntCmd - ZAddNX(key string, members ...*Z) *IntCmd - ZAddXX(key string, members ...*Z) *IntCmd - ZAddCh(key string, members ...*Z) *IntCmd - ZAddNXCh(key string, members ...*Z) *IntCmd - ZAddXXCh(key string, members ...*Z) *IntCmd - ZIncr(key string, member *Z) *FloatCmd - ZIncrNX(key string, member *Z) *FloatCmd - ZIncrXX(key string, member *Z) *FloatCmd - ZCard(key string) *IntCmd - ZCount(key, min, max string) *IntCmd - ZLexCount(key, min, max string) *IntCmd - ZIncrBy(key string, increment float64, member string) *FloatCmd - ZInterStore(destination string, store *ZStore) *IntCmd - ZPopMax(key string, count ...int64) *ZSliceCmd - ZPopMin(key string, count ...int64) *ZSliceCmd - ZRange(key string, start, stop int64) *StringSliceCmd - ZRangeWithScores(key string, start, stop int64) *ZSliceCmd - ZRangeByScore(key string, opt *ZRangeBy) *StringSliceCmd - ZRangeByLex(key string, opt *ZRangeBy) *StringSliceCmd - ZRangeByScoreWithScores(key string, opt *ZRangeBy) *ZSliceCmd - ZRank(key, member string) *IntCmd - ZRem(key string, members ...interface{}) *IntCmd - ZRemRangeByRank(key string, start, stop int64) *IntCmd - ZRemRangeByScore(key, min, max string) *IntCmd - ZRemRangeByLex(key, min, max string) *IntCmd - ZRevRange(key string, start, stop int64) *StringSliceCmd - ZRevRangeWithScores(key string, start, stop int64) *ZSliceCmd - ZRevRangeByScore(key string, opt *ZRangeBy) *StringSliceCmd - ZRevRangeByLex(key string, opt *ZRangeBy) *StringSliceCmd - ZRevRangeByScoreWithScores(key string, opt *ZRangeBy) *ZSliceCmd - ZRevRank(key, member string) *IntCmd - ZScore(key, member string) *FloatCmd - ZUnionStore(dest string, store *ZStore) *IntCmd - PFAdd(key string, els ...interface{}) *IntCmd - PFCount(keys ...string) *IntCmd - PFMerge(dest string, keys ...string) *StatusCmd - BgRewriteAOF() *StatusCmd - BgSave() *StatusCmd - ClientKill(ipPort string) *StatusCmd - ClientKillByFilter(keys ...string) *IntCmd - ClientList() *StringCmd - ClientPause(dur time.Duration) *BoolCmd - ClientID() *IntCmd - ConfigGet(parameter string) *SliceCmd - ConfigResetStat() *StatusCmd - ConfigSet(parameter, value string) *StatusCmd - ConfigRewrite() *StatusCmd - DBSize() *IntCmd - FlushAll() *StatusCmd - FlushAllAsync() *StatusCmd - FlushDB() *StatusCmd - FlushDBAsync() *StatusCmd - Info(section ...string) *StringCmd - LastSave() *IntCmd - Save() *StatusCmd - Shutdown() *StatusCmd - ShutdownSave() *StatusCmd - ShutdownNoSave() *StatusCmd - SlaveOf(host, port string) *StatusCmd - Time() *TimeCmd - Eval(script string, keys []string, args ...interface{}) *Cmd - EvalSha(sha1 string, keys []string, args ...interface{}) *Cmd - ScriptExists(hashes ...string) *BoolSliceCmd - ScriptFlush() *StatusCmd - ScriptKill() *StatusCmd - ScriptLoad(script string) *StringCmd - DebugObject(key string) *StringCmd - Publish(channel string, message interface{}) *IntCmd - PubSubChannels(pattern string) *StringSliceCmd - PubSubNumSub(channels ...string) *StringIntMapCmd - PubSubNumPat() *IntCmd - ClusterSlots() *ClusterSlotsCmd - ClusterNodes() *StringCmd - ClusterMeet(host, port string) *StatusCmd - ClusterForget(nodeID string) *StatusCmd - ClusterReplicate(nodeID string) *StatusCmd - ClusterResetSoft() *StatusCmd - ClusterResetHard() *StatusCmd - ClusterInfo() *StringCmd - ClusterKeySlot(key string) *IntCmd - ClusterGetKeysInSlot(slot int, count int) *StringSliceCmd - ClusterCountFailureReports(nodeID string) *IntCmd - ClusterCountKeysInSlot(slot int) *IntCmd - ClusterDelSlots(slots ...int) *StatusCmd - ClusterDelSlotsRange(min, max int) *StatusCmd - ClusterSaveConfig() *StatusCmd - ClusterSlaves(nodeID string) *StringSliceCmd - ClusterFailover() *StatusCmd - ClusterAddSlots(slots ...int) *StatusCmd - ClusterAddSlotsRange(min, max int) *StatusCmd - GeoAdd(key string, geoLocation ...*GeoLocation) *IntCmd - GeoPos(key string, members ...string) *GeoPosCmd - GeoRadius(key string, longitude, latitude float64, query *GeoRadiusQuery) *GeoLocationCmd - GeoRadiusStore(key string, longitude, latitude float64, query *GeoRadiusQuery) *IntCmd - GeoRadiusByMember(key, member string, query *GeoRadiusQuery) *GeoLocationCmd - GeoRadiusByMemberStore(key, member string, query *GeoRadiusQuery) *IntCmd - GeoDist(key string, member1, member2, unit string) *FloatCmd - GeoHash(key string, members ...string) *StringSliceCmd - ReadOnly() *StatusCmd - ReadWrite() *StatusCmd - MemoryUsage(key string, samples ...int) *IntCmd + Command(ctx context.Context) *CommandsInfoCmd + ClientGetName(ctx context.Context) *StringCmd + Echo(ctx context.Context, message interface{}) *StringCmd + Ping(ctx context.Context) *StatusCmd + Quit(ctx context.Context) *StatusCmd + Del(ctx context.Context, keys ...string) *IntCmd + Unlink(ctx context.Context, keys ...string) *IntCmd + Dump(ctx context.Context, key string) *StringCmd + Exists(ctx context.Context, keys ...string) *IntCmd + Expire(ctx context.Context, key string, expiration time.Duration) *BoolCmd + ExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd + Keys(ctx context.Context, pattern string) *StringSliceCmd + Migrate(ctx context.Context, host, port, key string, db int, timeout time.Duration) *StatusCmd + Move(ctx context.Context, key string, db int) *BoolCmd + ObjectRefCount(ctx context.Context, key string) *IntCmd + ObjectEncoding(ctx context.Context, key string) *StringCmd + ObjectIdleTime(ctx context.Context, key string) *DurationCmd + Persist(ctx context.Context, key string) *BoolCmd + PExpire(ctx context.Context, key string, expiration time.Duration) *BoolCmd + PExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd + PTTL(ctx context.Context, key string) *DurationCmd + RandomKey(ctx context.Context) *StringCmd + Rename(ctx context.Context, key, newkey string) *StatusCmd + RenameNX(ctx context.Context, key, newkey string) *BoolCmd + Restore(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd + RestoreReplace(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd + Sort(ctx context.Context, key string, sort *Sort) *StringSliceCmd + SortStore(ctx context.Context, key, store string, sort *Sort) *IntCmd + SortInterfaces(ctx context.Context, key string, sort *Sort) *SliceCmd + Touch(ctx context.Context, keys ...string) *IntCmd + TTL(ctx context.Context, key string) *DurationCmd + Type(ctx context.Context, key string) *StatusCmd + Append(ctx context.Context, key, value string) *IntCmd + Decr(ctx context.Context, key string) *IntCmd + DecrBy(ctx context.Context, key string, decrement int64) *IntCmd + Get(ctx context.Context, key string) *StringCmd + GetRange(ctx context.Context, key string, start, end int64) *StringCmd + GetSet(ctx context.Context, key string, value interface{}) *StringCmd + Incr(ctx context.Context, key string) *IntCmd + IncrBy(ctx context.Context, key string, value int64) *IntCmd + IncrByFloat(ctx context.Context, key string, value float64) *FloatCmd + MGet(ctx context.Context, keys ...string) *SliceCmd + MSet(ctx context.Context, values ...interface{}) *StatusCmd + MSetNX(ctx context.Context, values ...interface{}) *BoolCmd + Set(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd + SetNX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd + SetXX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd + SetRange(ctx context.Context, key string, offset int64, value string) *IntCmd + StrLen(ctx context.Context, key string) *IntCmd + + GetBit(ctx context.Context, key string, offset int64) *IntCmd + SetBit(ctx context.Context, key string, offset int64, value int) *IntCmd + BitCount(ctx context.Context, key string, bitCount *BitCount) *IntCmd + BitOpAnd(ctx context.Context, destKey string, keys ...string) *IntCmd + BitOpOr(ctx context.Context, destKey string, keys ...string) *IntCmd + BitOpXor(ctx context.Context, destKey string, keys ...string) *IntCmd + BitOpNot(ctx context.Context, destKey string, key string) *IntCmd + BitPos(ctx context.Context, key string, bit int64, pos ...int64) *IntCmd + BitField(ctx context.Context, key string, args ...interface{}) *IntSliceCmd + + Scan(ctx context.Context, cursor uint64, match string, count int64) *ScanCmd + SScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd + HScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd + ZScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd + + HDel(ctx context.Context, key string, fields ...string) *IntCmd + HExists(ctx context.Context, key, field string) *BoolCmd + HGet(ctx context.Context, key, field string) *StringCmd + HGetAll(ctx context.Context, key string) *StringStringMapCmd + HIncrBy(ctx context.Context, key, field string, incr int64) *IntCmd + HIncrByFloat(ctx context.Context, key, field string, incr float64) *FloatCmd + HKeys(ctx context.Context, key string) *StringSliceCmd + HLen(ctx context.Context, key string) *IntCmd + HMGet(ctx context.Context, key string, fields ...string) *SliceCmd + HSet(ctx context.Context, key string, values ...interface{}) *IntCmd + HMSet(ctx context.Context, key string, values ...interface{}) *BoolCmd + HSetNX(ctx context.Context, key, field string, value interface{}) *BoolCmd + HVals(ctx context.Context, key string) *StringSliceCmd + + BLPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd + BRPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd + BRPopLPush(ctx context.Context, source, destination string, timeout time.Duration) *StringCmd + LIndex(ctx context.Context, key string, index int64) *StringCmd + LInsert(ctx context.Context, key, op string, pivot, value interface{}) *IntCmd + LInsertBefore(ctx context.Context, key string, pivot, value interface{}) *IntCmd + LInsertAfter(ctx context.Context, key string, pivot, value interface{}) *IntCmd + LLen(ctx context.Context, key string) *IntCmd + LPop(ctx context.Context, key string) *StringCmd + LPush(ctx context.Context, key string, values ...interface{}) *IntCmd + LPushX(ctx context.Context, key string, values ...interface{}) *IntCmd + LRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd + LRem(ctx context.Context, key string, count int64, value interface{}) *IntCmd + LSet(ctx context.Context, key string, index int64, value interface{}) *StatusCmd + LTrim(ctx context.Context, key string, start, stop int64) *StatusCmd + RPop(ctx context.Context, key string) *StringCmd + RPopLPush(ctx context.Context, source, destination string) *StringCmd + RPush(ctx context.Context, key string, values ...interface{}) *IntCmd + RPushX(ctx context.Context, key string, values ...interface{}) *IntCmd + + SAdd(ctx context.Context, key string, members ...interface{}) *IntCmd + SCard(ctx context.Context, key string) *IntCmd + SDiff(ctx context.Context, keys ...string) *StringSliceCmd + SDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd + SInter(ctx context.Context, keys ...string) *StringSliceCmd + SInterStore(ctx context.Context, destination string, keys ...string) *IntCmd + SIsMember(ctx context.Context, key string, member interface{}) *BoolCmd + SMembers(ctx context.Context, key string) *StringSliceCmd + SMembersMap(ctx context.Context, key string) *StringStructMapCmd + SMove(ctx context.Context, source, destination string, member interface{}) *BoolCmd + SPop(ctx context.Context, key string) *StringCmd + SPopN(ctx context.Context, key string, count int64) *StringSliceCmd + SRandMember(ctx context.Context, key string) *StringCmd + SRandMemberN(ctx context.Context, key string, count int64) *StringSliceCmd + SRem(ctx context.Context, key string, members ...interface{}) *IntCmd + SUnion(ctx context.Context, keys ...string) *StringSliceCmd + SUnionStore(ctx context.Context, destination string, keys ...string) *IntCmd + + XAdd(ctx context.Context, a *XAddArgs) *StringCmd + XDel(ctx context.Context, stream string, ids ...string) *IntCmd + XLen(ctx context.Context, stream string) *IntCmd + XRange(ctx context.Context, stream, start, stop string) *XMessageSliceCmd + XRangeN(ctx context.Context, stream, start, stop string, count int64) *XMessageSliceCmd + XRevRange(ctx context.Context, stream string, start, stop string) *XMessageSliceCmd + XRevRangeN(ctx context.Context, stream string, start, stop string, count int64) *XMessageSliceCmd + XRead(ctx context.Context, a *XReadArgs) *XStreamSliceCmd + XReadStreams(ctx context.Context, streams ...string) *XStreamSliceCmd + XGroupCreate(ctx context.Context, stream, group, start string) *StatusCmd + XGroupCreateMkStream(ctx context.Context, stream, group, start string) *StatusCmd + XGroupSetID(ctx context.Context, stream, group, start string) *StatusCmd + XGroupDestroy(ctx context.Context, stream, group string) *IntCmd + XGroupDelConsumer(ctx context.Context, stream, group, consumer string) *IntCmd + XReadGroup(ctx context.Context, a *XReadGroupArgs) *XStreamSliceCmd + XAck(ctx context.Context, stream, group string, ids ...string) *IntCmd + XPending(ctx context.Context, stream, group string) *XPendingCmd + XPendingExt(ctx context.Context, a *XPendingExtArgs) *XPendingExtCmd + XClaim(ctx context.Context, a *XClaimArgs) *XMessageSliceCmd + XClaimJustID(ctx context.Context, a *XClaimArgs) *StringSliceCmd + XTrim(ctx context.Context, key string, maxLen int64) *IntCmd + XTrimApprox(ctx context.Context, key string, maxLen int64) *IntCmd + XInfoGroups(ctx context.Context, key string) *XInfoGroupsCmd + + BZPopMax(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd + BZPopMin(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd + ZAdd(ctx context.Context, key string, members ...*Z) *IntCmd + ZAddNX(ctx context.Context, key string, members ...*Z) *IntCmd + ZAddXX(ctx context.Context, key string, members ...*Z) *IntCmd + ZAddCh(ctx context.Context, key string, members ...*Z) *IntCmd + ZAddNXCh(ctx context.Context, key string, members ...*Z) *IntCmd + ZAddXXCh(ctx context.Context, key string, members ...*Z) *IntCmd + ZIncr(ctx context.Context, key string, member *Z) *FloatCmd + ZIncrNX(ctx context.Context, key string, member *Z) *FloatCmd + ZIncrXX(ctx context.Context, key string, member *Z) *FloatCmd + ZCard(ctx context.Context, key string) *IntCmd + ZCount(ctx context.Context, key, min, max string) *IntCmd + ZLexCount(ctx context.Context, key, min, max string) *IntCmd + ZIncrBy(ctx context.Context, key string, increment float64, member string) *FloatCmd + ZInterStore(ctx context.Context, destination string, store *ZStore) *IntCmd + ZPopMax(ctx context.Context, key string, count ...int64) *ZSliceCmd + ZPopMin(ctx context.Context, key string, count ...int64) *ZSliceCmd + ZRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd + ZRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd + ZRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd + ZRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd + ZRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd + ZRank(ctx context.Context, key, member string) *IntCmd + ZRem(ctx context.Context, key string, members ...interface{}) *IntCmd + ZRemRangeByRank(ctx context.Context, key string, start, stop int64) *IntCmd + ZRemRangeByScore(ctx context.Context, key, min, max string) *IntCmd + ZRemRangeByLex(ctx context.Context, key, min, max string) *IntCmd + ZRevRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd + ZRevRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd + ZRevRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd + ZRevRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd + ZRevRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd + ZRevRank(ctx context.Context, key, member string) *IntCmd + ZScore(ctx context.Context, key, member string) *FloatCmd + ZUnionStore(ctx context.Context, dest string, store *ZStore) *IntCmd + + PFAdd(ctx context.Context, key string, els ...interface{}) *IntCmd + PFCount(ctx context.Context, keys ...string) *IntCmd + PFMerge(ctx context.Context, dest string, keys ...string) *StatusCmd + + BgRewriteAOF(ctx context.Context) *StatusCmd + BgSave(ctx context.Context) *StatusCmd + ClientKill(ctx context.Context, ipPort string) *StatusCmd + ClientKillByFilter(ctx context.Context, keys ...string) *IntCmd + ClientList(ctx context.Context) *StringCmd + ClientPause(ctx context.Context, dur time.Duration) *BoolCmd + ClientID(ctx context.Context) *IntCmd + ConfigGet(ctx context.Context, parameter string) *SliceCmd + ConfigResetStat(ctx context.Context) *StatusCmd + ConfigSet(ctx context.Context, parameter, value string) *StatusCmd + ConfigRewrite(ctx context.Context) *StatusCmd + DBSize(ctx context.Context) *IntCmd + FlushAll(ctx context.Context) *StatusCmd + FlushAllAsync(ctx context.Context) *StatusCmd + FlushDB(ctx context.Context) *StatusCmd + FlushDBAsync(ctx context.Context) *StatusCmd + Info(ctx context.Context, section ...string) *StringCmd + LastSave(ctx context.Context) *IntCmd + Save(ctx context.Context) *StatusCmd + Shutdown(ctx context.Context) *StatusCmd + ShutdownSave(ctx context.Context) *StatusCmd + ShutdownNoSave(ctx context.Context) *StatusCmd + SlaveOf(ctx context.Context, host, port string) *StatusCmd + Time(ctx context.Context) *TimeCmd + DebugObject(ctx context.Context, key string) *StringCmd + ReadOnly(ctx context.Context) *StatusCmd + ReadWrite(ctx context.Context) *StatusCmd + MemoryUsage(ctx context.Context, key string, samples ...int) *IntCmd + + Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd + EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd + ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd + ScriptFlush(ctx context.Context) *StatusCmd + ScriptKill(ctx context.Context) *StatusCmd + ScriptLoad(ctx context.Context, script string) *StringCmd + + Publish(ctx context.Context, channel string, message interface{}) *IntCmd + PubSubChannels(ctx context.Context, pattern string) *StringSliceCmd + PubSubNumSub(ctx context.Context, channels ...string) *StringIntMapCmd + PubSubNumPat(ctx context.Context) *IntCmd + + ClusterSlots(ctx context.Context) *ClusterSlotsCmd + ClusterNodes(ctx context.Context) *StringCmd + ClusterMeet(ctx context.Context, host, port string) *StatusCmd + ClusterForget(ctx context.Context, nodeID string) *StatusCmd + ClusterReplicate(ctx context.Context, nodeID string) *StatusCmd + ClusterResetSoft(ctx context.Context) *StatusCmd + ClusterResetHard(ctx context.Context) *StatusCmd + ClusterInfo(ctx context.Context) *StringCmd + ClusterKeySlot(ctx context.Context, key string) *IntCmd + ClusterGetKeysInSlot(ctx context.Context, slot int, count int) *StringSliceCmd + ClusterCountFailureReports(ctx context.Context, nodeID string) *IntCmd + ClusterCountKeysInSlot(ctx context.Context, slot int) *IntCmd + ClusterDelSlots(ctx context.Context, slots ...int) *StatusCmd + ClusterDelSlotsRange(ctx context.Context, min, max int) *StatusCmd + ClusterSaveConfig(ctx context.Context) *StatusCmd + ClusterSlaves(ctx context.Context, nodeID string) *StringSliceCmd + ClusterFailover(ctx context.Context) *StatusCmd + ClusterAddSlots(ctx context.Context, slots ...int) *StatusCmd + ClusterAddSlotsRange(ctx context.Context, min, max int) *StatusCmd + + GeoAdd(ctx context.Context, key string, geoLocation ...*GeoLocation) *IntCmd + GeoPos(ctx context.Context, key string, members ...string) *GeoPosCmd + GeoRadius(ctx context.Context, key string, longitude, latitude float64, query *GeoRadiusQuery) *GeoLocationCmd + GeoRadiusStore(ctx context.Context, key string, longitude, latitude float64, query *GeoRadiusQuery) *IntCmd + GeoRadiusByMember(ctx context.Context, key, member string, query *GeoRadiusQuery) *GeoLocationCmd + GeoRadiusByMemberStore(ctx context.Context, key, member string, query *GeoRadiusQuery) *IntCmd + GeoDist(ctx context.Context, key string, member1, member2, unit string) *FloatCmd + GeoHash(ctx context.Context, key string, members ...string) *StringSliceCmd } type StatefulCmdable interface { Cmdable - Auth(password string) *StatusCmd - Select(index int) *StatusCmd - SwapDB(index1, index2 int) *StatusCmd - ClientSetName(name string) *BoolCmd + Auth(ctx context.Context, password string) *StatusCmd + Select(ctx context.Context, index int) *StatusCmd + SwapDB(ctx context.Context, index1, index2 int) *StatusCmd + ClientSetName(ctx context.Context, name string) *BoolCmd } var _ Cmdable = (*Client)(nil) @@ -312,119 +326,134 @@ var _ Cmdable = (*Tx)(nil) var _ Cmdable = (*Ring)(nil) var _ Cmdable = (*ClusterClient)(nil) -type cmdable func(cmd Cmder) error +type cmdable func(ctx context.Context, cmd Cmder) error -type statefulCmdable func(cmd Cmder) error +type statefulCmdable func(ctx context.Context, cmd Cmder) error //------------------------------------------------------------------------------ -func (c statefulCmdable) Auth(password string) *StatusCmd { - cmd := NewStatusCmd("auth", password) - _ = c(cmd) +func (c statefulCmdable) Auth(ctx context.Context, password string) *StatusCmd { + cmd := NewStatusCmd(ctx, "auth", password) + _ = c(ctx, cmd) return cmd } -func (c cmdable) Echo(message interface{}) *StringCmd { - cmd := NewStringCmd("echo", message) - _ = c(cmd) +func (c cmdable) Wait(ctx context.Context, numSlaves int, timeout time.Duration) *IntCmd { + cmd := NewIntCmd(ctx, "wait", numSlaves, int(timeout/time.Millisecond)) + _ = c(ctx, cmd) return cmd } -func (c cmdable) Ping() *StatusCmd { - cmd := NewStatusCmd("ping") - _ = c(cmd) +func (c statefulCmdable) Select(ctx context.Context, index int) *StatusCmd { + cmd := NewStatusCmd(ctx, "select", index) + _ = c(ctx, cmd) return cmd } -func (c cmdable) Wait(numSlaves int, timeout time.Duration) *IntCmd { - cmd := NewIntCmd("wait", numSlaves, int(timeout/time.Millisecond)) - _ = c(cmd) +func (c statefulCmdable) SwapDB(ctx context.Context, index1, index2 int) *StatusCmd { + cmd := NewStatusCmd(ctx, "swapdb", index1, index2) + _ = c(ctx, cmd) return cmd } -func (c cmdable) Quit() *StatusCmd { +// ClientSetName assigns a name to the connection. +func (c statefulCmdable) ClientSetName(ctx context.Context, name string) *BoolCmd { + cmd := NewBoolCmd(ctx, "client", "setname", name) + _ = c(ctx, cmd) + return cmd +} + +//------------------------------------------------------------------------------ + +func (c cmdable) Command(ctx context.Context) *CommandsInfoCmd { + cmd := NewCommandsInfoCmd(ctx, "command") + _ = c(ctx, cmd) + return cmd +} + +// ClientGetName returns the name of the connection. +func (c cmdable) ClientGetName(ctx context.Context) *StringCmd { + cmd := NewStringCmd(ctx, "client", "getname") + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) Echo(ctx context.Context, message interface{}) *StringCmd { + cmd := NewStringCmd(ctx, "echo", message) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) Ping(ctx context.Context) *StatusCmd { + cmd := NewStatusCmd(ctx, "ping") + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) Quit(ctx context.Context) *StatusCmd { panic("not implemented") } -func (c statefulCmdable) Select(index int) *StatusCmd { - cmd := NewStatusCmd("select", index) - _ = c(cmd) - return cmd -} - -func (c statefulCmdable) SwapDB(index1, index2 int) *StatusCmd { - cmd := NewStatusCmd("swapdb", index1, index2) - _ = c(cmd) - return cmd -} - -//------------------------------------------------------------------------------ - -func (c cmdable) Command() *CommandsInfoCmd { - cmd := NewCommandsInfoCmd("command") - _ = c(cmd) - return cmd -} - -func (c cmdable) Del(keys ...string) *IntCmd { +func (c cmdable) Del(ctx context.Context, keys ...string) *IntCmd { args := make([]interface{}, 1+len(keys)) args[0] = "del" for i, key := range keys { args[1+i] = key } - cmd := NewIntCmd(args...) - _ = c(cmd) + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) Unlink(keys ...string) *IntCmd { +func (c cmdable) Unlink(ctx context.Context, keys ...string) *IntCmd { args := make([]interface{}, 1+len(keys)) args[0] = "unlink" for i, key := range keys { args[1+i] = key } - cmd := NewIntCmd(args...) - _ = c(cmd) + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) Dump(key string) *StringCmd { - cmd := NewStringCmd("dump", key) - _ = c(cmd) +func (c cmdable) Dump(ctx context.Context, key string) *StringCmd { + cmd := NewStringCmd(ctx, "dump", key) + _ = c(ctx, cmd) return cmd } -func (c cmdable) Exists(keys ...string) *IntCmd { +func (c cmdable) Exists(ctx context.Context, keys ...string) *IntCmd { args := make([]interface{}, 1+len(keys)) args[0] = "exists" for i, key := range keys { args[1+i] = key } - cmd := NewIntCmd(args...) - _ = c(cmd) + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) Expire(key string, expiration time.Duration) *BoolCmd { - cmd := NewBoolCmd("expire", key, formatSec(expiration)) - _ = c(cmd) +func (c cmdable) Expire(ctx context.Context, key string, expiration time.Duration) *BoolCmd { + cmd := NewBoolCmd(ctx, "expire", key, formatSec(expiration)) + _ = c(ctx, cmd) return cmd } -func (c cmdable) ExpireAt(key string, tm time.Time) *BoolCmd { - cmd := NewBoolCmd("expireat", key, tm.Unix()) - _ = c(cmd) +func (c cmdable) ExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd { + cmd := NewBoolCmd(ctx, "expireat", key, tm.Unix()) + _ = c(ctx, cmd) return cmd } -func (c cmdable) Keys(pattern string) *StringSliceCmd { - cmd := NewStringSliceCmd("keys", pattern) - _ = c(cmd) +func (c cmdable) Keys(ctx context.Context, pattern string) *StringSliceCmd { + cmd := NewStringSliceCmd(ctx, "keys", pattern) + _ = c(ctx, cmd) return cmd } -func (c cmdable) Migrate(host, port, key string, db int, timeout time.Duration) *StatusCmd { +func (c cmdable) Migrate(ctx context.Context, host, port, key string, db int, timeout time.Duration) *StatusCmd { cmd := NewStatusCmd( + ctx, "migrate", host, port, @@ -433,100 +462,103 @@ func (c cmdable) Migrate(host, port, key string, db int, timeout time.Duration) formatMs(timeout), ) cmd.setReadTimeout(timeout) - _ = c(cmd) + _ = c(ctx, cmd) return cmd } -func (c cmdable) Move(key string, db int) *BoolCmd { - cmd := NewBoolCmd("move", key, db) - _ = c(cmd) +func (c cmdable) Move(ctx context.Context, key string, db int) *BoolCmd { + cmd := NewBoolCmd(ctx, "move", key, db) + _ = c(ctx, cmd) return cmd } -func (c cmdable) ObjectRefCount(key string) *IntCmd { - cmd := NewIntCmd("object", "refcount", key) - _ = c(cmd) +func (c cmdable) ObjectRefCount(ctx context.Context, key string) *IntCmd { + cmd := NewIntCmd(ctx, "object", "refcount", key) + _ = c(ctx, cmd) return cmd } -func (c cmdable) ObjectEncoding(key string) *StringCmd { - cmd := NewStringCmd("object", "encoding", key) - _ = c(cmd) +func (c cmdable) ObjectEncoding(ctx context.Context, key string) *StringCmd { + cmd := NewStringCmd(ctx, "object", "encoding", key) + _ = c(ctx, cmd) return cmd } -func (c cmdable) ObjectIdleTime(key string) *DurationCmd { - cmd := NewDurationCmd(time.Second, "object", "idletime", key) - _ = c(cmd) +func (c cmdable) ObjectIdleTime(ctx context.Context, key string) *DurationCmd { + cmd := NewDurationCmd(ctx, time.Second, "object", "idletime", key) + _ = c(ctx, cmd) return cmd } -func (c cmdable) Persist(key string) *BoolCmd { - cmd := NewBoolCmd("persist", key) - _ = c(cmd) +func (c cmdable) Persist(ctx context.Context, key string) *BoolCmd { + cmd := NewBoolCmd(ctx, "persist", key) + _ = c(ctx, cmd) return cmd } -func (c cmdable) PExpire(key string, expiration time.Duration) *BoolCmd { - cmd := NewBoolCmd("pexpire", key, formatMs(expiration)) - _ = c(cmd) +func (c cmdable) PExpire(ctx context.Context, key string, expiration time.Duration) *BoolCmd { + cmd := NewBoolCmd(ctx, "pexpire", key, formatMs(expiration)) + _ = c(ctx, cmd) return cmd } -func (c cmdable) PExpireAt(key string, tm time.Time) *BoolCmd { +func (c cmdable) PExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd { cmd := NewBoolCmd( + ctx, "pexpireat", key, tm.UnixNano()/int64(time.Millisecond), ) - _ = c(cmd) + _ = c(ctx, cmd) return cmd } -func (c cmdable) PTTL(key string) *DurationCmd { - cmd := NewDurationCmd(time.Millisecond, "pttl", key) - _ = c(cmd) +func (c cmdable) PTTL(ctx context.Context, key string) *DurationCmd { + cmd := NewDurationCmd(ctx, time.Millisecond, "pttl", key) + _ = c(ctx, cmd) return cmd } -func (c cmdable) RandomKey() *StringCmd { - cmd := NewStringCmd("randomkey") - _ = c(cmd) +func (c cmdable) RandomKey(ctx context.Context) *StringCmd { + cmd := NewStringCmd(ctx, "randomkey") + _ = c(ctx, cmd) return cmd } -func (c cmdable) Rename(key, newkey string) *StatusCmd { - cmd := NewStatusCmd("rename", key, newkey) - _ = c(cmd) +func (c cmdable) Rename(ctx context.Context, key, newkey string) *StatusCmd { + cmd := NewStatusCmd(ctx, "rename", key, newkey) + _ = c(ctx, cmd) return cmd } -func (c cmdable) RenameNX(key, newkey string) *BoolCmd { - cmd := NewBoolCmd("renamenx", key, newkey) - _ = c(cmd) +func (c cmdable) RenameNX(ctx context.Context, key, newkey string) *BoolCmd { + cmd := NewBoolCmd(ctx, "renamenx", key, newkey) + _ = c(ctx, cmd) return cmd } -func (c cmdable) Restore(key string, ttl time.Duration, value string) *StatusCmd { +func (c cmdable) Restore(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd { cmd := NewStatusCmd( + ctx, "restore", key, formatMs(ttl), value, ) - _ = c(cmd) + _ = c(ctx, cmd) return cmd } -func (c cmdable) RestoreReplace(key string, ttl time.Duration, value string) *StatusCmd { +func (c cmdable) RestoreReplace(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd { cmd := NewStatusCmd( + ctx, "restore", key, formatMs(ttl), value, "replace", ) - _ = c(cmd) + _ = c(ctx, cmd) return cmd } @@ -558,108 +590,230 @@ func (sort *Sort) args(key string) []interface{} { return args } -func (c cmdable) Sort(key string, sort *Sort) *StringSliceCmd { - cmd := NewStringSliceCmd(sort.args(key)...) - _ = c(cmd) +func (c cmdable) Sort(ctx context.Context, key string, sort *Sort) *StringSliceCmd { + cmd := NewStringSliceCmd(ctx, sort.args(key)...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) SortStore(key, store string, sort *Sort) *IntCmd { +func (c cmdable) SortStore(ctx context.Context, key, store string, sort *Sort) *IntCmd { args := sort.args(key) if store != "" { args = append(args, "store", store) } - cmd := NewIntCmd(args...) - _ = c(cmd) + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) SortInterfaces(key string, sort *Sort) *SliceCmd { - cmd := NewSliceCmd(sort.args(key)...) - _ = c(cmd) +func (c cmdable) SortInterfaces(ctx context.Context, key string, sort *Sort) *SliceCmd { + cmd := NewSliceCmd(ctx, sort.args(key)...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) Touch(keys ...string) *IntCmd { +func (c cmdable) Touch(ctx context.Context, keys ...string) *IntCmd { args := make([]interface{}, len(keys)+1) args[0] = "touch" for i, key := range keys { args[i+1] = key } - cmd := NewIntCmd(args...) - _ = c(cmd) + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) TTL(key string) *DurationCmd { - cmd := NewDurationCmd(time.Second, "ttl", key) - _ = c(cmd) +func (c cmdable) TTL(ctx context.Context, key string) *DurationCmd { + cmd := NewDurationCmd(ctx, time.Second, "ttl", key) + _ = c(ctx, cmd) return cmd } -func (c cmdable) Type(key string) *StatusCmd { - cmd := NewStatusCmd("type", key) - _ = c(cmd) +func (c cmdable) Type(ctx context.Context, key string) *StatusCmd { + cmd := NewStatusCmd(ctx, "type", key) + _ = c(ctx, cmd) return cmd } -func (c cmdable) Scan(cursor uint64, match string, count int64) *ScanCmd { - args := []interface{}{"scan", cursor} - if match != "" { - args = append(args, "match", match) - } - if count > 0 { - args = append(args, "count", count) - } - cmd := NewScanCmd(c, args...) - _ = c(cmd) +func (c cmdable) Append(ctx context.Context, key, value string) *IntCmd { + cmd := NewIntCmd(ctx, "append", key, value) + _ = c(ctx, cmd) return cmd } -func (c cmdable) SScan(key string, cursor uint64, match string, count int64) *ScanCmd { - args := []interface{}{"sscan", key, cursor} - if match != "" { - args = append(args, "match", match) - } - if count > 0 { - args = append(args, "count", count) - } - cmd := NewScanCmd(c, args...) - _ = c(cmd) +func (c cmdable) Decr(ctx context.Context, key string) *IntCmd { + cmd := NewIntCmd(ctx, "decr", key) + _ = c(ctx, cmd) return cmd } -func (c cmdable) HScan(key string, cursor uint64, match string, count int64) *ScanCmd { - args := []interface{}{"hscan", key, cursor} - if match != "" { - args = append(args, "match", match) - } - if count > 0 { - args = append(args, "count", count) - } - cmd := NewScanCmd(c, args...) - _ = c(cmd) +func (c cmdable) DecrBy(ctx context.Context, key string, decrement int64) *IntCmd { + cmd := NewIntCmd(ctx, "decrby", key, decrement) + _ = c(ctx, cmd) return cmd } -func (c cmdable) ZScan(key string, cursor uint64, match string, count int64) *ScanCmd { - args := []interface{}{"zscan", key, cursor} - if match != "" { - args = append(args, "match", match) +// Redis `GET key` command. It returns redis.Nil error when key does not exist. +func (c cmdable) Get(ctx context.Context, key string) *StringCmd { + cmd := NewStringCmd(ctx, "get", key) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) GetRange(ctx context.Context, key string, start, end int64) *StringCmd { + cmd := NewStringCmd(ctx, "getrange", key, start, end) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) GetSet(ctx context.Context, key string, value interface{}) *StringCmd { + cmd := NewStringCmd(ctx, "getset", key, value) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) Incr(ctx context.Context, key string) *IntCmd { + cmd := NewIntCmd(ctx, "incr", key) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) IncrBy(ctx context.Context, key string, value int64) *IntCmd { + cmd := NewIntCmd(ctx, "incrby", key, value) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) IncrByFloat(ctx context.Context, key string, value float64) *FloatCmd { + cmd := NewFloatCmd(ctx, "incrbyfloat", key, value) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) MGet(ctx context.Context, keys ...string) *SliceCmd { + args := make([]interface{}, 1+len(keys)) + args[0] = "mget" + for i, key := range keys { + args[1+i] = key } - if count > 0 { - args = append(args, "count", count) + cmd := NewSliceCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +// MSet is like Set but accepts multiple values: +// - MSet("key1", "value1", "key2", "value2") +// - MSet([]string{"key1", "value1", "key2", "value2"}) +// - MSet(map[string]interface{}{"key1": "value1", "key2": "value2"}) +func (c cmdable) MSet(ctx context.Context, values ...interface{}) *StatusCmd { + args := make([]interface{}, 1, 1+len(values)) + args[0] = "mset" + args = appendArgs(args, values) + cmd := NewStatusCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +// MSetNX is like SetNX but accepts multiple values: +// - MSetNX("key1", "value1", "key2", "value2") +// - MSetNX([]string{"key1", "value1", "key2", "value2"}) +// - MSetNX(map[string]interface{}{"key1": "value1", "key2": "value2"}) +func (c cmdable) MSetNX(ctx context.Context, values ...interface{}) *BoolCmd { + args := make([]interface{}, 1, 1+len(values)) + args[0] = "msetnx" + args = appendArgs(args, values) + cmd := NewBoolCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +// Redis `SET key value [expiration]` command. +// +// Use expiration for `SETEX`-like behavior. +// Zero expiration means the key has no expiration time. +func (c cmdable) Set(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd { + args := make([]interface{}, 3, 5) + args[0] = "set" + args[1] = key + args[2] = value + if expiration > 0 { + if usePrecise(expiration) { + args = append(args, "px", formatMs(expiration)) + } else { + args = append(args, "ex", formatSec(expiration)) + } } - cmd := NewScanCmd(c, args...) - _ = c(cmd) + cmd := NewStatusCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + +// Redis `SET key value [expiration] NX` command. +// +// Zero expiration means the key has no expiration time. +func (c cmdable) SetNX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd { + var cmd *BoolCmd + if expiration == 0 { + // Use old `SETNX` to support old Redis versions. + cmd = NewBoolCmd(ctx, "setnx", key, value) + } else { + if usePrecise(expiration) { + cmd = NewBoolCmd(ctx, "set", key, value, "px", formatMs(expiration), "nx") + } else { + cmd = NewBoolCmd(ctx, "set", key, value, "ex", formatSec(expiration), "nx") + } + } + _ = c(ctx, cmd) + return cmd +} + +// Redis `SET key value [expiration] XX` command. +// +// Zero expiration means the key has no expiration time. +func (c cmdable) SetXX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd { + var cmd *BoolCmd + if expiration == 0 { + cmd = NewBoolCmd(ctx, "set", key, value, "xx") + } else { + if usePrecise(expiration) { + cmd = NewBoolCmd(ctx, "set", key, value, "px", formatMs(expiration), "xx") + } else { + cmd = NewBoolCmd(ctx, "set", key, value, "ex", formatSec(expiration), "xx") + } + } + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) SetRange(ctx context.Context, key string, offset int64, value string) *IntCmd { + cmd := NewIntCmd(ctx, "setrange", key, offset, value) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) StrLen(ctx context.Context, key string) *IntCmd { + cmd := NewIntCmd(ctx, "strlen", key) + _ = c(ctx, cmd) return cmd } //------------------------------------------------------------------------------ -func (c cmdable) Append(key, value string) *IntCmd { - cmd := NewIntCmd("append", key, value) - _ = c(cmd) +func (c cmdable) GetBit(ctx context.Context, key string, offset int64) *IntCmd { + cmd := NewIntCmd(ctx, "getbit", key, offset) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) SetBit(ctx context.Context, key string, offset int64, value int) *IntCmd { + cmd := NewIntCmd( + ctx, + "setbit", + key, + offset, + value, + ) + _ = c(ctx, cmd) return cmd } @@ -667,7 +821,7 @@ type BitCount struct { Start, End int64 } -func (c cmdable) BitCount(key string, bitCount *BitCount) *IntCmd { +func (c cmdable) BitCount(ctx context.Context, key string, bitCount *BitCount) *IntCmd { args := []interface{}{"bitcount", key} if bitCount != nil { args = append( @@ -676,12 +830,12 @@ func (c cmdable) BitCount(key string, bitCount *BitCount) *IntCmd { bitCount.End, ) } - cmd := NewIntCmd(args...) - _ = c(cmd) + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) bitOp(op, destKey string, keys ...string) *IntCmd { +func (c cmdable) bitOp(ctx context.Context, op, destKey string, keys ...string) *IntCmd { args := make([]interface{}, 3+len(keys)) args[0] = "bitop" args[1] = op @@ -689,28 +843,28 @@ func (c cmdable) bitOp(op, destKey string, keys ...string) *IntCmd { for i, key := range keys { args[3+i] = key } - cmd := NewIntCmd(args...) - _ = c(cmd) + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) BitOpAnd(destKey string, keys ...string) *IntCmd { - return c.bitOp("and", destKey, keys...) +func (c cmdable) BitOpAnd(ctx context.Context, destKey string, keys ...string) *IntCmd { + return c.bitOp(ctx, "and", destKey, keys...) } -func (c cmdable) BitOpOr(destKey string, keys ...string) *IntCmd { - return c.bitOp("or", destKey, keys...) +func (c cmdable) BitOpOr(ctx context.Context, destKey string, keys ...string) *IntCmd { + return c.bitOp(ctx, "or", destKey, keys...) } -func (c cmdable) BitOpXor(destKey string, keys ...string) *IntCmd { - return c.bitOp("xor", destKey, keys...) +func (c cmdable) BitOpXor(ctx context.Context, destKey string, keys ...string) *IntCmd { + return c.bitOp(ctx, "xor", destKey, keys...) } -func (c cmdable) BitOpNot(destKey string, key string) *IntCmd { - return c.bitOp("not", destKey, key) +func (c cmdable) BitOpNot(ctx context.Context, destKey string, key string) *IntCmd { + return c.bitOp(ctx, "not", destKey, key) } -func (c cmdable) BitPos(key string, bit int64, pos ...int64) *IntCmd { +func (c cmdable) BitPos(ctx context.Context, key string, bit int64, pos ...int64) *IntCmd { args := make([]interface{}, 3+len(pos)) args[0] = "bitpos" args[1] = key @@ -725,261 +879,142 @@ func (c cmdable) BitPos(key string, bit int64, pos ...int64) *IntCmd { default: panic("too many arguments") } - cmd := NewIntCmd(args...) - _ = c(cmd) + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) BitField(key string, args ...interface{}) *IntSliceCmd { +func (c cmdable) BitField(ctx context.Context, key string, args ...interface{}) *IntSliceCmd { a := make([]interface{}, 0, 2+len(args)) a = append(a, "bitfield") a = append(a, key) a = append(a, args...) - cmd := NewIntSliceCmd(a...) - _ = c(cmd) - return cmd -} - -func (c cmdable) Decr(key string) *IntCmd { - cmd := NewIntCmd("decr", key) - _ = c(cmd) - return cmd -} - -func (c cmdable) DecrBy(key string, decrement int64) *IntCmd { - cmd := NewIntCmd("decrby", key, decrement) - _ = c(cmd) - return cmd -} - -// Redis `GET key` command. It returns redis.Nil error when key does not exist. -func (c cmdable) Get(key string) *StringCmd { - cmd := NewStringCmd("get", key) - _ = c(cmd) - return cmd -} - -func (c cmdable) GetBit(key string, offset int64) *IntCmd { - cmd := NewIntCmd("getbit", key, offset) - _ = c(cmd) - return cmd -} - -func (c cmdable) GetRange(key string, start, end int64) *StringCmd { - cmd := NewStringCmd("getrange", key, start, end) - _ = c(cmd) - return cmd -} - -func (c cmdable) GetSet(key string, value interface{}) *StringCmd { - cmd := NewStringCmd("getset", key, value) - _ = c(cmd) - return cmd -} - -func (c cmdable) Incr(key string) *IntCmd { - cmd := NewIntCmd("incr", key) - _ = c(cmd) - return cmd -} - -func (c cmdable) IncrBy(key string, value int64) *IntCmd { - cmd := NewIntCmd("incrby", key, value) - _ = c(cmd) - return cmd -} - -func (c cmdable) IncrByFloat(key string, value float64) *FloatCmd { - cmd := NewFloatCmd("incrbyfloat", key, value) - _ = c(cmd) - return cmd -} - -func (c cmdable) MGet(keys ...string) *SliceCmd { - args := make([]interface{}, 1+len(keys)) - args[0] = "mget" - for i, key := range keys { - args[1+i] = key - } - cmd := NewSliceCmd(args...) - _ = c(cmd) - return cmd -} - -// MSet is like Set but accepts multiple values: -// - MSet("key1", "value1", "key2", "value2") -// - MSet([]string{"key1", "value1", "key2", "value2"}) -// - MSet(map[string]interface{}{"key1": "value1", "key2": "value2"}) -func (c cmdable) MSet(values ...interface{}) *StatusCmd { - args := make([]interface{}, 1, 1+len(values)) - args[0] = "mset" - args = appendArgs(args, values) - cmd := NewStatusCmd(args...) - _ = c(cmd) - return cmd -} - -// MSetNX is like SetNX but accepts multiple values: -// - MSetNX("key1", "value1", "key2", "value2") -// - MSetNX([]string{"key1", "value1", "key2", "value2"}) -// - MSetNX(map[string]interface{}{"key1": "value1", "key2": "value2"}) -func (c cmdable) MSetNX(values ...interface{}) *BoolCmd { - args := make([]interface{}, 1, 1+len(values)) - args[0] = "msetnx" - args = appendArgs(args, values) - cmd := NewBoolCmd(args...) - _ = c(cmd) - return cmd -} - -// Redis `SET key value [expiration]` command. -// -// Use expiration for `SETEX`-like behavior. -// Zero expiration means the key has no expiration time. -func (c cmdable) Set(key string, value interface{}, expiration time.Duration) *StatusCmd { - args := make([]interface{}, 3, 5) - args[0] = "set" - args[1] = key - args[2] = value - if expiration > 0 { - if usePrecise(expiration) { - args = append(args, "px", formatMs(expiration)) - } else { - args = append(args, "ex", formatSec(expiration)) - } - } - cmd := NewStatusCmd(args...) - _ = c(cmd) - return cmd -} - -func (c cmdable) SetBit(key string, offset int64, value int) *IntCmd { - cmd := NewIntCmd( - "setbit", - key, - offset, - value, - ) - _ = c(cmd) - return cmd -} - -// Redis `SET key value [expiration] NX` command. -// -// Zero expiration means the key has no expiration time. -func (c cmdable) SetNX(key string, value interface{}, expiration time.Duration) *BoolCmd { - var cmd *BoolCmd - if expiration == 0 { - // Use old `SETNX` to support old Redis versions. - cmd = NewBoolCmd("setnx", key, value) - } else { - if usePrecise(expiration) { - cmd = NewBoolCmd("set", key, value, "px", formatMs(expiration), "nx") - } else { - cmd = NewBoolCmd("set", key, value, "ex", formatSec(expiration), "nx") - } - } - _ = c(cmd) - return cmd -} - -// Redis `SET key value [expiration] XX` command. -// -// Zero expiration means the key has no expiration time. -func (c cmdable) SetXX(key string, value interface{}, expiration time.Duration) *BoolCmd { - var cmd *BoolCmd - if expiration == 0 { - cmd = NewBoolCmd("set", key, value, "xx") - } else { - if usePrecise(expiration) { - cmd = NewBoolCmd("set", key, value, "px", formatMs(expiration), "xx") - } else { - cmd = NewBoolCmd("set", key, value, "ex", formatSec(expiration), "xx") - } - } - _ = c(cmd) - return cmd -} - -func (c cmdable) SetRange(key string, offset int64, value string) *IntCmd { - cmd := NewIntCmd("setrange", key, offset, value) - _ = c(cmd) - return cmd -} - -func (c cmdable) StrLen(key string) *IntCmd { - cmd := NewIntCmd("strlen", key) - _ = c(cmd) + cmd := NewIntSliceCmd(ctx, a...) + _ = c(ctx, cmd) return cmd } //------------------------------------------------------------------------------ -func (c cmdable) HDel(key string, fields ...string) *IntCmd { +func (c cmdable) Scan(ctx context.Context, cursor uint64, match string, count int64) *ScanCmd { + args := []interface{}{"scan", cursor} + if match != "" { + args = append(args, "match", match) + } + if count > 0 { + args = append(args, "count", count) + } + cmd := NewScanCmd(ctx, c, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) SScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd { + args := []interface{}{"sscan", key, cursor} + if match != "" { + args = append(args, "match", match) + } + if count > 0 { + args = append(args, "count", count) + } + cmd := NewScanCmd(ctx, c, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) HScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd { + args := []interface{}{"hscan", key, cursor} + if match != "" { + args = append(args, "match", match) + } + if count > 0 { + args = append(args, "count", count) + } + cmd := NewScanCmd(ctx, c, args...) + _ = c(ctx, cmd) + return cmd +} + +func (c cmdable) ZScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd { + args := []interface{}{"zscan", key, cursor} + if match != "" { + args = append(args, "match", match) + } + if count > 0 { + args = append(args, "count", count) + } + cmd := NewScanCmd(ctx, c, args...) + _ = c(ctx, cmd) + return cmd +} + +//------------------------------------------------------------------------------ + +func (c cmdable) HDel(ctx context.Context, key string, fields ...string) *IntCmd { args := make([]interface{}, 2+len(fields)) args[0] = "hdel" args[1] = key for i, field := range fields { args[2+i] = field } - cmd := NewIntCmd(args...) - _ = c(cmd) + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) HExists(key, field string) *BoolCmd { - cmd := NewBoolCmd("hexists", key, field) - _ = c(cmd) +func (c cmdable) HExists(ctx context.Context, key, field string) *BoolCmd { + cmd := NewBoolCmd(ctx, "hexists", key, field) + _ = c(ctx, cmd) return cmd } -func (c cmdable) HGet(key, field string) *StringCmd { - cmd := NewStringCmd("hget", key, field) - _ = c(cmd) +func (c cmdable) HGet(ctx context.Context, key, field string) *StringCmd { + cmd := NewStringCmd(ctx, "hget", key, field) + _ = c(ctx, cmd) return cmd } -func (c cmdable) HGetAll(key string) *StringStringMapCmd { - cmd := NewStringStringMapCmd("hgetall", key) - _ = c(cmd) +func (c cmdable) HGetAll(ctx context.Context, key string) *StringStringMapCmd { + cmd := NewStringStringMapCmd(ctx, "hgetall", key) + _ = c(ctx, cmd) return cmd } -func (c cmdable) HIncrBy(key, field string, incr int64) *IntCmd { - cmd := NewIntCmd("hincrby", key, field, incr) - _ = c(cmd) +func (c cmdable) HIncrBy(ctx context.Context, key, field string, incr int64) *IntCmd { + cmd := NewIntCmd(ctx, "hincrby", key, field, incr) + _ = c(ctx, cmd) return cmd } -func (c cmdable) HIncrByFloat(key, field string, incr float64) *FloatCmd { - cmd := NewFloatCmd("hincrbyfloat", key, field, incr) - _ = c(cmd) +func (c cmdable) HIncrByFloat(ctx context.Context, key, field string, incr float64) *FloatCmd { + cmd := NewFloatCmd(ctx, "hincrbyfloat", key, field, incr) + _ = c(ctx, cmd) return cmd } -func (c cmdable) HKeys(key string) *StringSliceCmd { - cmd := NewStringSliceCmd("hkeys", key) - _ = c(cmd) +func (c cmdable) HKeys(ctx context.Context, key string) *StringSliceCmd { + cmd := NewStringSliceCmd(ctx, "hkeys", key) + _ = c(ctx, cmd) return cmd } -func (c cmdable) HLen(key string) *IntCmd { - cmd := NewIntCmd("hlen", key) - _ = c(cmd) +func (c cmdable) HLen(ctx context.Context, key string) *IntCmd { + cmd := NewIntCmd(ctx, "hlen", key) + _ = c(ctx, cmd) return cmd } // HMGet returns the values for the specified fields in the hash stored at key. // It returns an interface{} to distinguish between empty string and nil value. -func (c cmdable) HMGet(key string, fields ...string) *SliceCmd { +func (c cmdable) HMGet(ctx context.Context, key string, fields ...string) *SliceCmd { args := make([]interface{}, 2+len(fields)) args[0] = "hmget" args[1] = key for i, field := range fields { args[2+i] = field } - cmd := NewSliceCmd(args...) - _ = c(cmd) + cmd := NewSliceCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } @@ -989,349 +1024,352 @@ func (c cmdable) HMGet(key string, fields ...string) *SliceCmd { // - HMSet("myhash", map[string]interface{}{"key1": "value1", "key2": "value2"}) // // Note that it requires Redis v4 for multiple field/value pairs support. -func (c cmdable) HSet(key string, values ...interface{}) *IntCmd { +func (c cmdable) HSet(ctx context.Context, key string, values ...interface{}) *IntCmd { args := make([]interface{}, 2, 2+len(values)) args[0] = "hset" args[1] = key args = appendArgs(args, values) - cmd := NewIntCmd(args...) - _ = c(cmd) + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } // HMSet is a deprecated version of HSet left for compatibility with Redis 3. -func (c cmdable) HMSet(key string, values ...interface{}) *BoolCmd { +func (c cmdable) HMSet(ctx context.Context, key string, values ...interface{}) *BoolCmd { args := make([]interface{}, 2, 2+len(values)) args[0] = "hmset" args[1] = key args = appendArgs(args, values) - cmd := NewBoolCmd(args...) - _ = c(cmd) + cmd := NewBoolCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) HSetNX(key, field string, value interface{}) *BoolCmd { - cmd := NewBoolCmd("hsetnx", key, field, value) - _ = c(cmd) +func (c cmdable) HSetNX(ctx context.Context, key, field string, value interface{}) *BoolCmd { + cmd := NewBoolCmd(ctx, "hsetnx", key, field, value) + _ = c(ctx, cmd) return cmd } -func (c cmdable) HVals(key string) *StringSliceCmd { - cmd := NewStringSliceCmd("hvals", key) - _ = c(cmd) +func (c cmdable) HVals(ctx context.Context, key string) *StringSliceCmd { + cmd := NewStringSliceCmd(ctx, "hvals", key) + _ = c(ctx, cmd) return cmd } //------------------------------------------------------------------------------ -func (c cmdable) BLPop(timeout time.Duration, keys ...string) *StringSliceCmd { +func (c cmdable) BLPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd { args := make([]interface{}, 1+len(keys)+1) args[0] = "blpop" for i, key := range keys { args[1+i] = key } args[len(args)-1] = formatSec(timeout) - cmd := NewStringSliceCmd(args...) + cmd := NewStringSliceCmd(ctx, args...) cmd.setReadTimeout(timeout) - _ = c(cmd) + _ = c(ctx, cmd) return cmd } -func (c cmdable) BRPop(timeout time.Duration, keys ...string) *StringSliceCmd { +func (c cmdable) BRPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd { args := make([]interface{}, 1+len(keys)+1) args[0] = "brpop" for i, key := range keys { args[1+i] = key } args[len(keys)+1] = formatSec(timeout) - cmd := NewStringSliceCmd(args...) + cmd := NewStringSliceCmd(ctx, args...) cmd.setReadTimeout(timeout) - _ = c(cmd) + _ = c(ctx, cmd) return cmd } -func (c cmdable) BRPopLPush(source, destination string, timeout time.Duration) *StringCmd { +func (c cmdable) BRPopLPush(ctx context.Context, source, destination string, timeout time.Duration) *StringCmd { cmd := NewStringCmd( + ctx, "brpoplpush", source, destination, formatSec(timeout), ) cmd.setReadTimeout(timeout) - _ = c(cmd) + _ = c(ctx, cmd) return cmd } -func (c cmdable) LIndex(key string, index int64) *StringCmd { - cmd := NewStringCmd("lindex", key, index) - _ = c(cmd) +func (c cmdable) LIndex(ctx context.Context, key string, index int64) *StringCmd { + cmd := NewStringCmd(ctx, "lindex", key, index) + _ = c(ctx, cmd) return cmd } -func (c cmdable) LInsert(key, op string, pivot, value interface{}) *IntCmd { - cmd := NewIntCmd("linsert", key, op, pivot, value) - _ = c(cmd) +func (c cmdable) LInsert(ctx context.Context, key, op string, pivot, value interface{}) *IntCmd { + cmd := NewIntCmd(ctx, "linsert", key, op, pivot, value) + _ = c(ctx, cmd) return cmd } -func (c cmdable) LInsertBefore(key string, pivot, value interface{}) *IntCmd { - cmd := NewIntCmd("linsert", key, "before", pivot, value) - _ = c(cmd) +func (c cmdable) LInsertBefore(ctx context.Context, key string, pivot, value interface{}) *IntCmd { + cmd := NewIntCmd(ctx, "linsert", key, "before", pivot, value) + _ = c(ctx, cmd) return cmd } -func (c cmdable) LInsertAfter(key string, pivot, value interface{}) *IntCmd { - cmd := NewIntCmd("linsert", key, "after", pivot, value) - _ = c(cmd) +func (c cmdable) LInsertAfter(ctx context.Context, key string, pivot, value interface{}) *IntCmd { + cmd := NewIntCmd(ctx, "linsert", key, "after", pivot, value) + _ = c(ctx, cmd) return cmd } -func (c cmdable) LLen(key string) *IntCmd { - cmd := NewIntCmd("llen", key) - _ = c(cmd) +func (c cmdable) LLen(ctx context.Context, key string) *IntCmd { + cmd := NewIntCmd(ctx, "llen", key) + _ = c(ctx, cmd) return cmd } -func (c cmdable) LPop(key string) *StringCmd { - cmd := NewStringCmd("lpop", key) - _ = c(cmd) +func (c cmdable) LPop(ctx context.Context, key string) *StringCmd { + cmd := NewStringCmd(ctx, "lpop", key) + _ = c(ctx, cmd) return cmd } -func (c cmdable) LPush(key string, values ...interface{}) *IntCmd { +func (c cmdable) LPush(ctx context.Context, key string, values ...interface{}) *IntCmd { args := make([]interface{}, 2, 2+len(values)) args[0] = "lpush" args[1] = key args = appendArgs(args, values) - cmd := NewIntCmd(args...) - _ = c(cmd) + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) LPushX(key string, values ...interface{}) *IntCmd { +func (c cmdable) LPushX(ctx context.Context, key string, values ...interface{}) *IntCmd { args := make([]interface{}, 2, 2+len(values)) args[0] = "lpushx" args[1] = key args = appendArgs(args, values) - cmd := NewIntCmd(args...) - _ = c(cmd) + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) LRange(key string, start, stop int64) *StringSliceCmd { +func (c cmdable) LRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd { cmd := NewStringSliceCmd( + ctx, "lrange", key, start, stop, ) - _ = c(cmd) + _ = c(ctx, cmd) return cmd } -func (c cmdable) LRem(key string, count int64, value interface{}) *IntCmd { - cmd := NewIntCmd("lrem", key, count, value) - _ = c(cmd) +func (c cmdable) LRem(ctx context.Context, key string, count int64, value interface{}) *IntCmd { + cmd := NewIntCmd(ctx, "lrem", key, count, value) + _ = c(ctx, cmd) return cmd } -func (c cmdable) LSet(key string, index int64, value interface{}) *StatusCmd { - cmd := NewStatusCmd("lset", key, index, value) - _ = c(cmd) +func (c cmdable) LSet(ctx context.Context, key string, index int64, value interface{}) *StatusCmd { + cmd := NewStatusCmd(ctx, "lset", key, index, value) + _ = c(ctx, cmd) return cmd } -func (c cmdable) LTrim(key string, start, stop int64) *StatusCmd { +func (c cmdable) LTrim(ctx context.Context, key string, start, stop int64) *StatusCmd { cmd := NewStatusCmd( + ctx, "ltrim", key, start, stop, ) - _ = c(cmd) + _ = c(ctx, cmd) return cmd } -func (c cmdable) RPop(key string) *StringCmd { - cmd := NewStringCmd("rpop", key) - _ = c(cmd) +func (c cmdable) RPop(ctx context.Context, key string) *StringCmd { + cmd := NewStringCmd(ctx, "rpop", key) + _ = c(ctx, cmd) return cmd } -func (c cmdable) RPopLPush(source, destination string) *StringCmd { - cmd := NewStringCmd("rpoplpush", source, destination) - _ = c(cmd) +func (c cmdable) RPopLPush(ctx context.Context, source, destination string) *StringCmd { + cmd := NewStringCmd(ctx, "rpoplpush", source, destination) + _ = c(ctx, cmd) return cmd } -func (c cmdable) RPush(key string, values ...interface{}) *IntCmd { +func (c cmdable) RPush(ctx context.Context, key string, values ...interface{}) *IntCmd { args := make([]interface{}, 2, 2+len(values)) args[0] = "rpush" args[1] = key args = appendArgs(args, values) - cmd := NewIntCmd(args...) - _ = c(cmd) + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) RPushX(key string, values ...interface{}) *IntCmd { +func (c cmdable) RPushX(ctx context.Context, key string, values ...interface{}) *IntCmd { args := make([]interface{}, 2, 2+len(values)) args[0] = "rpushx" args[1] = key args = appendArgs(args, values) - cmd := NewIntCmd(args...) - _ = c(cmd) + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } //------------------------------------------------------------------------------ -func (c cmdable) SAdd(key string, members ...interface{}) *IntCmd { +func (c cmdable) SAdd(ctx context.Context, key string, members ...interface{}) *IntCmd { args := make([]interface{}, 2, 2+len(members)) args[0] = "sadd" args[1] = key args = appendArgs(args, members) - cmd := NewIntCmd(args...) - _ = c(cmd) + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) SCard(key string) *IntCmd { - cmd := NewIntCmd("scard", key) - _ = c(cmd) +func (c cmdable) SCard(ctx context.Context, key string) *IntCmd { + cmd := NewIntCmd(ctx, "scard", key) + _ = c(ctx, cmd) return cmd } -func (c cmdable) SDiff(keys ...string) *StringSliceCmd { +func (c cmdable) SDiff(ctx context.Context, keys ...string) *StringSliceCmd { args := make([]interface{}, 1+len(keys)) args[0] = "sdiff" for i, key := range keys { args[1+i] = key } - cmd := NewStringSliceCmd(args...) - _ = c(cmd) + cmd := NewStringSliceCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) SDiffStore(destination string, keys ...string) *IntCmd { +func (c cmdable) SDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd { args := make([]interface{}, 2+len(keys)) args[0] = "sdiffstore" args[1] = destination for i, key := range keys { args[2+i] = key } - cmd := NewIntCmd(args...) - _ = c(cmd) + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) SInter(keys ...string) *StringSliceCmd { +func (c cmdable) SInter(ctx context.Context, keys ...string) *StringSliceCmd { args := make([]interface{}, 1+len(keys)) args[0] = "sinter" for i, key := range keys { args[1+i] = key } - cmd := NewStringSliceCmd(args...) - _ = c(cmd) + cmd := NewStringSliceCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) SInterStore(destination string, keys ...string) *IntCmd { +func (c cmdable) SInterStore(ctx context.Context, destination string, keys ...string) *IntCmd { args := make([]interface{}, 2+len(keys)) args[0] = "sinterstore" args[1] = destination for i, key := range keys { args[2+i] = key } - cmd := NewIntCmd(args...) - _ = c(cmd) + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) SIsMember(key string, member interface{}) *BoolCmd { - cmd := NewBoolCmd("sismember", key, member) - _ = c(cmd) +func (c cmdable) SIsMember(ctx context.Context, key string, member interface{}) *BoolCmd { + cmd := NewBoolCmd(ctx, "sismember", key, member) + _ = c(ctx, cmd) return cmd } // Redis `SMEMBERS key` command output as a slice -func (c cmdable) SMembers(key string) *StringSliceCmd { - cmd := NewStringSliceCmd("smembers", key) - _ = c(cmd) +func (c cmdable) SMembers(ctx context.Context, key string) *StringSliceCmd { + cmd := NewStringSliceCmd(ctx, "smembers", key) + _ = c(ctx, cmd) return cmd } // Redis `SMEMBERS key` command output as a map -func (c cmdable) SMembersMap(key string) *StringStructMapCmd { - cmd := NewStringStructMapCmd("smembers", key) - _ = c(cmd) +func (c cmdable) SMembersMap(ctx context.Context, key string) *StringStructMapCmd { + cmd := NewStringStructMapCmd(ctx, "smembers", key) + _ = c(ctx, cmd) return cmd } -func (c cmdable) SMove(source, destination string, member interface{}) *BoolCmd { - cmd := NewBoolCmd("smove", source, destination, member) - _ = c(cmd) +func (c cmdable) SMove(ctx context.Context, source, destination string, member interface{}) *BoolCmd { + cmd := NewBoolCmd(ctx, "smove", source, destination, member) + _ = c(ctx, cmd) return cmd } // Redis `SPOP key` command. -func (c cmdable) SPop(key string) *StringCmd { - cmd := NewStringCmd("spop", key) - _ = c(cmd) +func (c cmdable) SPop(ctx context.Context, key string) *StringCmd { + cmd := NewStringCmd(ctx, "spop", key) + _ = c(ctx, cmd) return cmd } // Redis `SPOP key count` command. -func (c cmdable) SPopN(key string, count int64) *StringSliceCmd { - cmd := NewStringSliceCmd("spop", key, count) - _ = c(cmd) +func (c cmdable) SPopN(ctx context.Context, key string, count int64) *StringSliceCmd { + cmd := NewStringSliceCmd(ctx, "spop", key, count) + _ = c(ctx, cmd) return cmd } // Redis `SRANDMEMBER key` command. -func (c cmdable) SRandMember(key string) *StringCmd { - cmd := NewStringCmd("srandmember", key) - _ = c(cmd) +func (c cmdable) SRandMember(ctx context.Context, key string) *StringCmd { + cmd := NewStringCmd(ctx, "srandmember", key) + _ = c(ctx, cmd) return cmd } // Redis `SRANDMEMBER key count` command. -func (c cmdable) SRandMemberN(key string, count int64) *StringSliceCmd { - cmd := NewStringSliceCmd("srandmember", key, count) - _ = c(cmd) +func (c cmdable) SRandMemberN(ctx context.Context, key string, count int64) *StringSliceCmd { + cmd := NewStringSliceCmd(ctx, "srandmember", key, count) + _ = c(ctx, cmd) return cmd } -func (c cmdable) SRem(key string, members ...interface{}) *IntCmd { +func (c cmdable) SRem(ctx context.Context, key string, members ...interface{}) *IntCmd { args := make([]interface{}, 2, 2+len(members)) args[0] = "srem" args[1] = key args = appendArgs(args, members) - cmd := NewIntCmd(args...) - _ = c(cmd) + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) SUnion(keys ...string) *StringSliceCmd { +func (c cmdable) SUnion(ctx context.Context, keys ...string) *StringSliceCmd { args := make([]interface{}, 1+len(keys)) args[0] = "sunion" for i, key := range keys { args[1+i] = key } - cmd := NewStringSliceCmd(args...) - _ = c(cmd) + cmd := NewStringSliceCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) SUnionStore(destination string, keys ...string) *IntCmd { +func (c cmdable) SUnionStore(ctx context.Context, destination string, keys ...string) *IntCmd { args := make([]interface{}, 2+len(keys)) args[0] = "sunionstore" args[1] = destination for i, key := range keys { args[2+i] = key } - cmd := NewIntCmd(args...) - _ = c(cmd) + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } @@ -1345,7 +1383,7 @@ type XAddArgs struct { Values map[string]interface{} } -func (c cmdable) XAdd(a *XAddArgs) *StringCmd { +func (c cmdable) XAdd(ctx context.Context, a *XAddArgs) *StringCmd { args := make([]interface{}, 0, 6+len(a.Values)*2) args = append(args, "xadd") args = append(args, a.Stream) @@ -1364,48 +1402,48 @@ func (c cmdable) XAdd(a *XAddArgs) *StringCmd { args = append(args, v) } - cmd := NewStringCmd(args...) - _ = c(cmd) + cmd := NewStringCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) XDel(stream string, ids ...string) *IntCmd { +func (c cmdable) XDel(ctx context.Context, stream string, ids ...string) *IntCmd { args := []interface{}{"xdel", stream} for _, id := range ids { args = append(args, id) } - cmd := NewIntCmd(args...) - _ = c(cmd) + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) XLen(stream string) *IntCmd { - cmd := NewIntCmd("xlen", stream) - _ = c(cmd) +func (c cmdable) XLen(ctx context.Context, stream string) *IntCmd { + cmd := NewIntCmd(ctx, "xlen", stream) + _ = c(ctx, cmd) return cmd } -func (c cmdable) XRange(stream, start, stop string) *XMessageSliceCmd { - cmd := NewXMessageSliceCmd("xrange", stream, start, stop) - _ = c(cmd) +func (c cmdable) XRange(ctx context.Context, stream, start, stop string) *XMessageSliceCmd { + cmd := NewXMessageSliceCmd(ctx, "xrange", stream, start, stop) + _ = c(ctx, cmd) return cmd } -func (c cmdable) XRangeN(stream, start, stop string, count int64) *XMessageSliceCmd { - cmd := NewXMessageSliceCmd("xrange", stream, start, stop, "count", count) - _ = c(cmd) +func (c cmdable) XRangeN(ctx context.Context, stream, start, stop string, count int64) *XMessageSliceCmd { + cmd := NewXMessageSliceCmd(ctx, "xrange", stream, start, stop, "count", count) + _ = c(ctx, cmd) return cmd } -func (c cmdable) XRevRange(stream, start, stop string) *XMessageSliceCmd { - cmd := NewXMessageSliceCmd("xrevrange", stream, start, stop) - _ = c(cmd) +func (c cmdable) XRevRange(ctx context.Context, stream, start, stop string) *XMessageSliceCmd { + cmd := NewXMessageSliceCmd(ctx, "xrevrange", stream, start, stop) + _ = c(ctx, cmd) return cmd } -func (c cmdable) XRevRangeN(stream, start, stop string, count int64) *XMessageSliceCmd { - cmd := NewXMessageSliceCmd("xrevrange", stream, start, stop, "count", count) - _ = c(cmd) +func (c cmdable) XRevRangeN(ctx context.Context, stream, start, stop string, count int64) *XMessageSliceCmd { + cmd := NewXMessageSliceCmd(ctx, "xrevrange", stream, start, stop, "count", count) + _ = c(ctx, cmd) return cmd } @@ -1415,7 +1453,7 @@ type XReadArgs struct { Block time.Duration } -func (c cmdable) XRead(a *XReadArgs) *XStreamSliceCmd { +func (c cmdable) XRead(ctx context.Context, a *XReadArgs) *XStreamSliceCmd { args := make([]interface{}, 0, 5+len(a.Streams)) args = append(args, "xread") if a.Count > 0 { @@ -1432,48 +1470,48 @@ func (c cmdable) XRead(a *XReadArgs) *XStreamSliceCmd { args = append(args, s) } - cmd := NewXStreamSliceCmd(args...) + cmd := NewXStreamSliceCmd(ctx, args...) if a.Block >= 0 { cmd.setReadTimeout(a.Block) } - _ = c(cmd) + _ = c(ctx, cmd) return cmd } -func (c cmdable) XReadStreams(streams ...string) *XStreamSliceCmd { - return c.XRead(&XReadArgs{ +func (c cmdable) XReadStreams(ctx context.Context, streams ...string) *XStreamSliceCmd { + return c.XRead(ctx, &XReadArgs{ Streams: streams, Block: -1, }) } -func (c cmdable) XGroupCreate(stream, group, start string) *StatusCmd { - cmd := NewStatusCmd("xgroup", "create", stream, group, start) - _ = c(cmd) +func (c cmdable) XGroupCreate(ctx context.Context, stream, group, start string) *StatusCmd { + cmd := NewStatusCmd(ctx, "xgroup", "create", stream, group, start) + _ = c(ctx, cmd) return cmd } -func (c cmdable) XGroupCreateMkStream(stream, group, start string) *StatusCmd { - cmd := NewStatusCmd("xgroup", "create", stream, group, start, "mkstream") - _ = c(cmd) +func (c cmdable) XGroupCreateMkStream(ctx context.Context, stream, group, start string) *StatusCmd { + cmd := NewStatusCmd(ctx, "xgroup", "create", stream, group, start, "mkstream") + _ = c(ctx, cmd) return cmd } -func (c cmdable) XGroupSetID(stream, group, start string) *StatusCmd { - cmd := NewStatusCmd("xgroup", "setid", stream, group, start) - _ = c(cmd) +func (c cmdable) XGroupSetID(ctx context.Context, stream, group, start string) *StatusCmd { + cmd := NewStatusCmd(ctx, "xgroup", "setid", stream, group, start) + _ = c(ctx, cmd) return cmd } -func (c cmdable) XGroupDestroy(stream, group string) *IntCmd { - cmd := NewIntCmd("xgroup", "destroy", stream, group) - _ = c(cmd) +func (c cmdable) XGroupDestroy(ctx context.Context, stream, group string) *IntCmd { + cmd := NewIntCmd(ctx, "xgroup", "destroy", stream, group) + _ = c(ctx, cmd) return cmd } -func (c cmdable) XGroupDelConsumer(stream, group, consumer string) *IntCmd { - cmd := NewIntCmd("xgroup", "delconsumer", stream, group, consumer) - _ = c(cmd) +func (c cmdable) XGroupDelConsumer(ctx context.Context, stream, group, consumer string) *IntCmd { + cmd := NewIntCmd(ctx, "xgroup", "delconsumer", stream, group, consumer) + _ = c(ctx, cmd) return cmd } @@ -1486,7 +1524,7 @@ type XReadGroupArgs struct { NoAck bool } -func (c cmdable) XReadGroup(a *XReadGroupArgs) *XStreamSliceCmd { +func (c cmdable) XReadGroup(ctx context.Context, a *XReadGroupArgs) *XStreamSliceCmd { args := make([]interface{}, 0, 8+len(a.Streams)) args = append(args, "xreadgroup", "group", a.Group, a.Consumer) if a.Count > 0 { @@ -1503,27 +1541,27 @@ func (c cmdable) XReadGroup(a *XReadGroupArgs) *XStreamSliceCmd { args = append(args, s) } - cmd := NewXStreamSliceCmd(args...) + cmd := NewXStreamSliceCmd(ctx, args...) if a.Block >= 0 { cmd.setReadTimeout(a.Block) } - _ = c(cmd) + _ = c(ctx, cmd) return cmd } -func (c cmdable) XAck(stream, group string, ids ...string) *IntCmd { +func (c cmdable) XAck(ctx context.Context, stream, group string, ids ...string) *IntCmd { args := []interface{}{"xack", stream, group} for _, id := range ids { args = append(args, id) } - cmd := NewIntCmd(args...) - _ = c(cmd) + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) XPending(stream, group string) *XPendingCmd { - cmd := NewXPendingCmd("xpending", stream, group) - _ = c(cmd) +func (c cmdable) XPending(ctx context.Context, stream, group string) *XPendingCmd { + cmd := NewXPendingCmd(ctx, "xpending", stream, group) + _ = c(ctx, cmd) return cmd } @@ -1536,14 +1574,14 @@ type XPendingExtArgs struct { Consumer string } -func (c cmdable) XPendingExt(a *XPendingExtArgs) *XPendingExtCmd { +func (c cmdable) XPendingExt(ctx context.Context, a *XPendingExtArgs) *XPendingExtCmd { args := make([]interface{}, 0, 7) args = append(args, "xpending", a.Stream, a.Group, a.Start, a.End, a.Count) if a.Consumer != "" { args = append(args, a.Consumer) } - cmd := NewXPendingExtCmd(args...) - _ = c(cmd) + cmd := NewXPendingExtCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } @@ -1555,18 +1593,18 @@ type XClaimArgs struct { Messages []string } -func (c cmdable) XClaim(a *XClaimArgs) *XMessageSliceCmd { +func (c cmdable) XClaim(ctx context.Context, a *XClaimArgs) *XMessageSliceCmd { args := xClaimArgs(a) - cmd := NewXMessageSliceCmd(args...) - _ = c(cmd) + cmd := NewXMessageSliceCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) XClaimJustID(a *XClaimArgs) *StringSliceCmd { +func (c cmdable) XClaimJustID(ctx context.Context, a *XClaimArgs) *StringSliceCmd { args := xClaimArgs(a) args = append(args, "justid") - cmd := NewStringSliceCmd(args...) - _ = c(cmd) + cmd := NewStringSliceCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } @@ -1583,21 +1621,21 @@ func xClaimArgs(a *XClaimArgs) []interface{} { return args } -func (c cmdable) XTrim(key string, maxLen int64) *IntCmd { - cmd := NewIntCmd("xtrim", key, "maxlen", maxLen) - _ = c(cmd) +func (c cmdable) XTrim(ctx context.Context, key string, maxLen int64) *IntCmd { + cmd := NewIntCmd(ctx, "xtrim", key, "maxlen", maxLen) + _ = c(ctx, cmd) return cmd } -func (c cmdable) XTrimApprox(key string, maxLen int64) *IntCmd { - cmd := NewIntCmd("xtrim", key, "maxlen", "~", maxLen) - _ = c(cmd) +func (c cmdable) XTrimApprox(ctx context.Context, key string, maxLen int64) *IntCmd { + cmd := NewIntCmd(ctx, "xtrim", key, "maxlen", "~", maxLen) + _ = c(ctx, cmd) return cmd } -func (c cmdable) XInfoGroups(key string) *XInfoGroupsCmd { - cmd := NewXInfoGroupsCmd(key) - _ = c(cmd) +func (c cmdable) XInfoGroups(ctx context.Context, key string) *XInfoGroupsCmd { + cmd := NewXInfoGroupsCmd(ctx, key) + _ = c(ctx, cmd) return cmd } @@ -1624,150 +1662,150 @@ type ZStore struct { } // Redis `BZPOPMAX key [key ...] timeout` command. -func (c cmdable) BZPopMax(timeout time.Duration, keys ...string) *ZWithKeyCmd { +func (c cmdable) BZPopMax(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd { args := make([]interface{}, 1+len(keys)+1) args[0] = "bzpopmax" for i, key := range keys { args[1+i] = key } args[len(args)-1] = formatSec(timeout) - cmd := NewZWithKeyCmd(args...) + cmd := NewZWithKeyCmd(ctx, args...) cmd.setReadTimeout(timeout) - _ = c(cmd) + _ = c(ctx, cmd) return cmd } // Redis `BZPOPMIN key [key ...] timeout` command. -func (c cmdable) BZPopMin(timeout time.Duration, keys ...string) *ZWithKeyCmd { +func (c cmdable) BZPopMin(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd { args := make([]interface{}, 1+len(keys)+1) args[0] = "bzpopmin" for i, key := range keys { args[1+i] = key } args[len(args)-1] = formatSec(timeout) - cmd := NewZWithKeyCmd(args...) + cmd := NewZWithKeyCmd(ctx, args...) cmd.setReadTimeout(timeout) - _ = c(cmd) + _ = c(ctx, cmd) return cmd } -func (c cmdable) zAdd(a []interface{}, n int, members ...*Z) *IntCmd { +func (c cmdable) zAdd(ctx context.Context, a []interface{}, n int, members ...*Z) *IntCmd { for i, m := range members { a[n+2*i] = m.Score a[n+2*i+1] = m.Member } - cmd := NewIntCmd(a...) - _ = c(cmd) + cmd := NewIntCmd(ctx, a...) + _ = c(ctx, cmd) return cmd } // Redis `ZADD key score member [score member ...]` command. -func (c cmdable) ZAdd(key string, members ...*Z) *IntCmd { +func (c cmdable) ZAdd(ctx context.Context, key string, members ...*Z) *IntCmd { const n = 2 a := make([]interface{}, n+2*len(members)) a[0], a[1] = "zadd", key - return c.zAdd(a, n, members...) + return c.zAdd(ctx, a, n, members...) } // Redis `ZADD key NX score member [score member ...]` command. -func (c cmdable) ZAddNX(key string, members ...*Z) *IntCmd { +func (c cmdable) ZAddNX(ctx context.Context, key string, members ...*Z) *IntCmd { const n = 3 a := make([]interface{}, n+2*len(members)) a[0], a[1], a[2] = "zadd", key, "nx" - return c.zAdd(a, n, members...) + return c.zAdd(ctx, a, n, members...) } // Redis `ZADD key XX score member [score member ...]` command. -func (c cmdable) ZAddXX(key string, members ...*Z) *IntCmd { +func (c cmdable) ZAddXX(ctx context.Context, key string, members ...*Z) *IntCmd { const n = 3 a := make([]interface{}, n+2*len(members)) a[0], a[1], a[2] = "zadd", key, "xx" - return c.zAdd(a, n, members...) + return c.zAdd(ctx, a, n, members...) } // Redis `ZADD key CH score member [score member ...]` command. -func (c cmdable) ZAddCh(key string, members ...*Z) *IntCmd { +func (c cmdable) ZAddCh(ctx context.Context, key string, members ...*Z) *IntCmd { const n = 3 a := make([]interface{}, n+2*len(members)) a[0], a[1], a[2] = "zadd", key, "ch" - return c.zAdd(a, n, members...) + return c.zAdd(ctx, a, n, members...) } // Redis `ZADD key NX CH score member [score member ...]` command. -func (c cmdable) ZAddNXCh(key string, members ...*Z) *IntCmd { +func (c cmdable) ZAddNXCh(ctx context.Context, key string, members ...*Z) *IntCmd { const n = 4 a := make([]interface{}, n+2*len(members)) a[0], a[1], a[2], a[3] = "zadd", key, "nx", "ch" - return c.zAdd(a, n, members...) + return c.zAdd(ctx, a, n, members...) } // Redis `ZADD key XX CH score member [score member ...]` command. -func (c cmdable) ZAddXXCh(key string, members ...*Z) *IntCmd { +func (c cmdable) ZAddXXCh(ctx context.Context, key string, members ...*Z) *IntCmd { const n = 4 a := make([]interface{}, n+2*len(members)) a[0], a[1], a[2], a[3] = "zadd", key, "xx", "ch" - return c.zAdd(a, n, members...) + return c.zAdd(ctx, a, n, members...) } -func (c cmdable) zIncr(a []interface{}, n int, members ...*Z) *FloatCmd { +func (c cmdable) zIncr(ctx context.Context, a []interface{}, n int, members ...*Z) *FloatCmd { for i, m := range members { a[n+2*i] = m.Score a[n+2*i+1] = m.Member } - cmd := NewFloatCmd(a...) - _ = c(cmd) + cmd := NewFloatCmd(ctx, a...) + _ = c(ctx, cmd) return cmd } // Redis `ZADD key INCR score member` command. -func (c cmdable) ZIncr(key string, member *Z) *FloatCmd { +func (c cmdable) ZIncr(ctx context.Context, key string, member *Z) *FloatCmd { const n = 3 a := make([]interface{}, n+2) a[0], a[1], a[2] = "zadd", key, "incr" - return c.zIncr(a, n, member) + return c.zIncr(ctx, a, n, member) } // Redis `ZADD key NX INCR score member` command. -func (c cmdable) ZIncrNX(key string, member *Z) *FloatCmd { +func (c cmdable) ZIncrNX(ctx context.Context, key string, member *Z) *FloatCmd { const n = 4 a := make([]interface{}, n+2) a[0], a[1], a[2], a[3] = "zadd", key, "incr", "nx" - return c.zIncr(a, n, member) + return c.zIncr(ctx, a, n, member) } // Redis `ZADD key XX INCR score member` command. -func (c cmdable) ZIncrXX(key string, member *Z) *FloatCmd { +func (c cmdable) ZIncrXX(ctx context.Context, key string, member *Z) *FloatCmd { const n = 4 a := make([]interface{}, n+2) a[0], a[1], a[2], a[3] = "zadd", key, "incr", "xx" - return c.zIncr(a, n, member) + return c.zIncr(ctx, a, n, member) } -func (c cmdable) ZCard(key string) *IntCmd { - cmd := NewIntCmd("zcard", key) - _ = c(cmd) +func (c cmdable) ZCard(ctx context.Context, key string) *IntCmd { + cmd := NewIntCmd(ctx, "zcard", key) + _ = c(ctx, cmd) return cmd } -func (c cmdable) ZCount(key, min, max string) *IntCmd { - cmd := NewIntCmd("zcount", key, min, max) - _ = c(cmd) +func (c cmdable) ZCount(ctx context.Context, key, min, max string) *IntCmd { + cmd := NewIntCmd(ctx, "zcount", key, min, max) + _ = c(ctx, cmd) return cmd } -func (c cmdable) ZLexCount(key, min, max string) *IntCmd { - cmd := NewIntCmd("zlexcount", key, min, max) - _ = c(cmd) +func (c cmdable) ZLexCount(ctx context.Context, key, min, max string) *IntCmd { + cmd := NewIntCmd(ctx, "zlexcount", key, min, max) + _ = c(ctx, cmd) return cmd } -func (c cmdable) ZIncrBy(key string, increment float64, member string) *FloatCmd { - cmd := NewFloatCmd("zincrby", key, increment, member) - _ = c(cmd) +func (c cmdable) ZIncrBy(ctx context.Context, key string, increment float64, member string) *FloatCmd { + cmd := NewFloatCmd(ctx, "zincrby", key, increment, member) + _ = c(ctx, cmd) return cmd } -func (c cmdable) ZInterStore(destination string, store *ZStore) *IntCmd { +func (c cmdable) ZInterStore(ctx context.Context, destination string, store *ZStore) *IntCmd { args := make([]interface{}, 3+len(store.Keys)) args[0] = "zinterstore" args[1] = destination @@ -1784,12 +1822,12 @@ func (c cmdable) ZInterStore(destination string, store *ZStore) *IntCmd { if store.Aggregate != "" { args = append(args, "aggregate", store.Aggregate) } - cmd := NewIntCmd(args...) - _ = c(cmd) + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) ZPopMax(key string, count ...int64) *ZSliceCmd { +func (c cmdable) ZPopMax(ctx context.Context, key string, count ...int64) *ZSliceCmd { args := []interface{}{ "zpopmax", key, @@ -1804,12 +1842,12 @@ func (c cmdable) ZPopMax(key string, count ...int64) *ZSliceCmd { panic("too many arguments") } - cmd := NewZSliceCmd(args...) - _ = c(cmd) + cmd := NewZSliceCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) ZPopMin(key string, count ...int64) *ZSliceCmd { +func (c cmdable) ZPopMin(ctx context.Context, key string, count ...int64) *ZSliceCmd { args := []interface{}{ "zpopmin", key, @@ -1824,12 +1862,12 @@ func (c cmdable) ZPopMin(key string, count ...int64) *ZSliceCmd { panic("too many arguments") } - cmd := NewZSliceCmd(args...) - _ = c(cmd) + cmd := NewZSliceCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) zRange(key string, start, stop int64, withScores bool) *StringSliceCmd { +func (c cmdable) zRange(ctx context.Context, key string, start, stop int64, withScores bool) *StringSliceCmd { args := []interface{}{ "zrange", key, @@ -1839,18 +1877,18 @@ func (c cmdable) zRange(key string, start, stop int64, withScores bool) *StringS if withScores { args = append(args, "withscores") } - cmd := NewStringSliceCmd(args...) - _ = c(cmd) + cmd := NewStringSliceCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) ZRange(key string, start, stop int64) *StringSliceCmd { - return c.zRange(key, start, stop, false) +func (c cmdable) ZRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd { + return c.zRange(ctx, key, start, stop, false) } -func (c cmdable) ZRangeWithScores(key string, start, stop int64) *ZSliceCmd { - cmd := NewZSliceCmd("zrange", key, start, stop, "withscores") - _ = c(cmd) +func (c cmdable) ZRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd { + cmd := NewZSliceCmd(ctx, "zrange", key, start, stop, "withscores") + _ = c(ctx, cmd) return cmd } @@ -1859,7 +1897,7 @@ type ZRangeBy struct { Offset, Count int64 } -func (c cmdable) zRangeBy(zcmd, key string, opt *ZRangeBy, withScores bool) *StringSliceCmd { +func (c cmdable) zRangeBy(ctx context.Context, zcmd, key string, opt *ZRangeBy, withScores bool) *StringSliceCmd { args := []interface{}{zcmd, key, opt.Min, opt.Max} if withScores { args = append(args, "withscores") @@ -1872,20 +1910,20 @@ func (c cmdable) zRangeBy(zcmd, key string, opt *ZRangeBy, withScores bool) *Str opt.Count, ) } - cmd := NewStringSliceCmd(args...) - _ = c(cmd) + cmd := NewStringSliceCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) ZRangeByScore(key string, opt *ZRangeBy) *StringSliceCmd { - return c.zRangeBy("zrangebyscore", key, opt, false) +func (c cmdable) ZRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd { + return c.zRangeBy(ctx, "zrangebyscore", key, opt, false) } -func (c cmdable) ZRangeByLex(key string, opt *ZRangeBy) *StringSliceCmd { - return c.zRangeBy("zrangebylex", key, opt, false) +func (c cmdable) ZRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd { + return c.zRangeBy(ctx, "zrangebylex", key, opt, false) } -func (c cmdable) ZRangeByScoreWithScores(key string, opt *ZRangeBy) *ZSliceCmd { +func (c cmdable) ZRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd { args := []interface{}{"zrangebyscore", key, opt.Min, opt.Max, "withscores"} if opt.Offset != 0 || opt.Count != 0 { args = append( @@ -1895,63 +1933,64 @@ func (c cmdable) ZRangeByScoreWithScores(key string, opt *ZRangeBy) *ZSliceCmd { opt.Count, ) } - cmd := NewZSliceCmd(args...) - _ = c(cmd) + cmd := NewZSliceCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) ZRank(key, member string) *IntCmd { - cmd := NewIntCmd("zrank", key, member) - _ = c(cmd) +func (c cmdable) ZRank(ctx context.Context, key, member string) *IntCmd { + cmd := NewIntCmd(ctx, "zrank", key, member) + _ = c(ctx, cmd) return cmd } -func (c cmdable) ZRem(key string, members ...interface{}) *IntCmd { +func (c cmdable) ZRem(ctx context.Context, key string, members ...interface{}) *IntCmd { args := make([]interface{}, 2, 2+len(members)) args[0] = "zrem" args[1] = key args = appendArgs(args, members) - cmd := NewIntCmd(args...) - _ = c(cmd) + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) ZRemRangeByRank(key string, start, stop int64) *IntCmd { +func (c cmdable) ZRemRangeByRank(ctx context.Context, key string, start, stop int64) *IntCmd { cmd := NewIntCmd( + ctx, "zremrangebyrank", key, start, stop, ) - _ = c(cmd) + _ = c(ctx, cmd) return cmd } -func (c cmdable) ZRemRangeByScore(key, min, max string) *IntCmd { - cmd := NewIntCmd("zremrangebyscore", key, min, max) - _ = c(cmd) +func (c cmdable) ZRemRangeByScore(ctx context.Context, key, min, max string) *IntCmd { + cmd := NewIntCmd(ctx, "zremrangebyscore", key, min, max) + _ = c(ctx, cmd) return cmd } -func (c cmdable) ZRemRangeByLex(key, min, max string) *IntCmd { - cmd := NewIntCmd("zremrangebylex", key, min, max) - _ = c(cmd) +func (c cmdable) ZRemRangeByLex(ctx context.Context, key, min, max string) *IntCmd { + cmd := NewIntCmd(ctx, "zremrangebylex", key, min, max) + _ = c(ctx, cmd) return cmd } -func (c cmdable) ZRevRange(key string, start, stop int64) *StringSliceCmd { - cmd := NewStringSliceCmd("zrevrange", key, start, stop) - _ = c(cmd) +func (c cmdable) ZRevRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd { + cmd := NewStringSliceCmd(ctx, "zrevrange", key, start, stop) + _ = c(ctx, cmd) return cmd } -func (c cmdable) ZRevRangeWithScores(key string, start, stop int64) *ZSliceCmd { - cmd := NewZSliceCmd("zrevrange", key, start, stop, "withscores") - _ = c(cmd) +func (c cmdable) ZRevRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd { + cmd := NewZSliceCmd(ctx, "zrevrange", key, start, stop, "withscores") + _ = c(ctx, cmd) return cmd } -func (c cmdable) zRevRangeBy(zcmd, key string, opt *ZRangeBy) *StringSliceCmd { +func (c cmdable) zRevRangeBy(ctx context.Context, zcmd, key string, opt *ZRangeBy) *StringSliceCmd { args := []interface{}{zcmd, key, opt.Max, opt.Min} if opt.Offset != 0 || opt.Count != 0 { args = append( @@ -1961,20 +2000,20 @@ func (c cmdable) zRevRangeBy(zcmd, key string, opt *ZRangeBy) *StringSliceCmd { opt.Count, ) } - cmd := NewStringSliceCmd(args...) - _ = c(cmd) + cmd := NewStringSliceCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) ZRevRangeByScore(key string, opt *ZRangeBy) *StringSliceCmd { - return c.zRevRangeBy("zrevrangebyscore", key, opt) +func (c cmdable) ZRevRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd { + return c.zRevRangeBy(ctx, "zrevrangebyscore", key, opt) } -func (c cmdable) ZRevRangeByLex(key string, opt *ZRangeBy) *StringSliceCmd { - return c.zRevRangeBy("zrevrangebylex", key, opt) +func (c cmdable) ZRevRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd { + return c.zRevRangeBy(ctx, "zrevrangebylex", key, opt) } -func (c cmdable) ZRevRangeByScoreWithScores(key string, opt *ZRangeBy) *ZSliceCmd { +func (c cmdable) ZRevRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd { args := []interface{}{"zrevrangebyscore", key, opt.Max, opt.Min, "withscores"} if opt.Offset != 0 || opt.Count != 0 { args = append( @@ -1984,24 +2023,24 @@ func (c cmdable) ZRevRangeByScoreWithScores(key string, opt *ZRangeBy) *ZSliceCm opt.Count, ) } - cmd := NewZSliceCmd(args...) - _ = c(cmd) + cmd := NewZSliceCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) ZRevRank(key, member string) *IntCmd { - cmd := NewIntCmd("zrevrank", key, member) - _ = c(cmd) +func (c cmdable) ZRevRank(ctx context.Context, key, member string) *IntCmd { + cmd := NewIntCmd(ctx, "zrevrank", key, member) + _ = c(ctx, cmd) return cmd } -func (c cmdable) ZScore(key, member string) *FloatCmd { - cmd := NewFloatCmd("zscore", key, member) - _ = c(cmd) +func (c cmdable) ZScore(ctx context.Context, key, member string) *FloatCmd { + cmd := NewFloatCmd(ctx, "zscore", key, member) + _ = c(ctx, cmd) return cmd } -func (c cmdable) ZUnionStore(dest string, store *ZStore) *IntCmd { +func (c cmdable) ZUnionStore(ctx context.Context, dest string, store *ZStore) *IntCmd { args := make([]interface{}, 3+len(store.Keys)) args[0] = "zunionstore" args[1] = dest @@ -2018,214 +2057,195 @@ func (c cmdable) ZUnionStore(dest string, store *ZStore) *IntCmd { if store.Aggregate != "" { args = append(args, "aggregate", store.Aggregate) } - cmd := NewIntCmd(args...) - _ = c(cmd) + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } //------------------------------------------------------------------------------ -func (c cmdable) PFAdd(key string, els ...interface{}) *IntCmd { +func (c cmdable) PFAdd(ctx context.Context, key string, els ...interface{}) *IntCmd { args := make([]interface{}, 2, 2+len(els)) args[0] = "pfadd" args[1] = key args = appendArgs(args, els) - cmd := NewIntCmd(args...) - _ = c(cmd) + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) PFCount(keys ...string) *IntCmd { +func (c cmdable) PFCount(ctx context.Context, keys ...string) *IntCmd { args := make([]interface{}, 1+len(keys)) args[0] = "pfcount" for i, key := range keys { args[1+i] = key } - cmd := NewIntCmd(args...) - _ = c(cmd) + cmd := NewIntCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } -func (c cmdable) PFMerge(dest string, keys ...string) *StatusCmd { +func (c cmdable) PFMerge(ctx context.Context, dest string, keys ...string) *StatusCmd { args := make([]interface{}, 2+len(keys)) args[0] = "pfmerge" args[1] = dest for i, key := range keys { args[2+i] = key } - cmd := NewStatusCmd(args...) - _ = c(cmd) + cmd := NewStatusCmd(ctx, args...) + _ = c(ctx, cmd) return cmd } //------------------------------------------------------------------------------ -func (c cmdable) BgRewriteAOF() *StatusCmd { - cmd := NewStatusCmd("bgrewriteaof") - _ = c(cmd) +func (c cmdable) BgRewriteAOF(ctx context.Context) *StatusCmd { + cmd := NewStatusCmd(ctx, "bgrewriteaof") + _ = c(ctx, cmd) return cmd } -func (c cmdable) BgSave() *StatusCmd { - cmd := NewStatusCmd("bgsave") - _ = c(cmd) +func (c cmdable) BgSave(ctx context.Context) *StatusCmd { + cmd := NewStatusCmd(ctx, "bgsave") + _ = c(ctx, cmd) return cmd } -func (c cmdable) ClientKill(ipPort string) *StatusCmd { - cmd := NewStatusCmd("client", "kill", ipPort) - _ = c(cmd) +func (c cmdable) ClientKill(ctx context.Context, ipPort string) *StatusCmd { + cmd := NewStatusCmd(ctx, "client", "kill", ipPort) + _ = c(ctx, cmd) return cmd } -// ClientKillByFilter is new style synx, while the ClientKill is old +// ClientKillByFilter is new style syntax, while the ClientKill is old // CLIENT KILL