Documentation ¶
Overview ¶
Package redis is a client for the Redis database.
Example (Zpop) ¶
This example implements ZPOP as described at http://redis.io/topics/transactions using WATCH/MULTI/EXEC and scripting.
package main import ( "context" "fmt" "github.com/weiwenchen2022/go-redis" ) // zpop pops a value from the ZSET key using WATCH/MULTI/EXEC commands. func zpop(ctx context.Context, rdb *redis.Client, key string) (result string, err error) { // Loop until transaction is successful. for { err = rdb.Watch(ctx, func(tx *redis.Tx) error { members, err := tx.Do(ctx, "ZRANGE", key, 0, 0).Strings() if err != nil { return err } if len(members) != 1 { return redis.ErrNil } _, err = tx.TxPipelined(ctx, func(pipe redis.Pipeliner) error { pipe.Send("ZREM", key, members[0]) return nil }) if err == nil { result = members[0] } return err }, key) switch err { default: // Return any other error. return "", err case nil: // Success. return result, nil case redis.TxFailedErr: // Optimistic lock lost. Retry. } } } // zpopScript pops a value from a ZSET. var zpopScript = redis.NewScript(` local r = redis.call('ZRANGE', KEYS[1], 0, 0) if r ~= nil then r = r[1] redis.call('ZREM', KEYS[1], r) end return r `) // This example implements ZPOP as described at // http://redis.io/topics/transactions using WATCH/MULTI/EXEC and scripting. func main() { var ( ctx = context.Background() rdb = redis.NewClient(&redis.Options{ Addr: "localhost:6379", }) ) // Add test data using a pipeline. if _, err := rdb.Pipelined(ctx, func(pipe redis.Pipeliner) error { for i, member := range []string{"red", "blue", "green"} { pipe.Send("ZADD", "zset", i, member) } return nil }); err != nil { panic(err) } // Pop using WATCH/MULTI/EXEC v, err := zpop(ctx, rdb, "zset") if err != nil { panic(err) } fmt.Println(v) // Pop using a script. v, err = zpopScript.Run(ctx, rdb, []string{"zset"}).String() if err != nil { panic(err) } fmt.Println(v) }
Output: red blue
Index ¶
- Constants
- Variables
- type Args
- type ChannelOption
- type Client
- func (p Client) Close() error
- func (p Client) Conn() *Conn
- func (p Client) Do(ctx context.Context, commandName string, args ...any) *Result
- func (p Client) Eval(ctx context.Context, script string, keys []string, args ...any) *Result
- func (p Client) EvalRO(ctx context.Context, script string, keys []string, args ...interface{}) *Result
- func (p Client) EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Result
- func (p Client) EvalShaRO(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Result
- func (p Client) PSubscribe(ctx context.Context, patterns ...string) *PubSub
- func (p Client) Pipeline() Pipeliner
- func (p Client) Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]*Result, error)
- func (p Client) PoolStats() PoolStats
- func (p Client) ScriptExists(ctx context.Context, hashes ...string) *Result
- func (p Client) ScriptFlush(ctx context.Context) *Result
- func (p Client) ScriptLoad(ctx context.Context, script string) *Result
- func (p Client) Subscribe(ctx context.Context, channels ...string) *PubSub
- func (p Client) TxPipeline() Pipeliner
- func (p Client) TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]*Result, error)
- func (p Client) Watch(ctx context.Context, fn func(*Tx) error, keys ...string) error
- type Conn
- func (c *Conn) Close() error
- func (c *Conn) Do(ctx context.Context, commandName string, args ...any) *Result
- func (c *Conn) Err() error
- func (c Conn) Eval(ctx context.Context, script string, keys []string, args ...any) *Result
- func (c Conn) EvalRO(ctx context.Context, script string, keys []string, args ...any) *Result
- func (c Conn) EvalSha(ctx context.Context, sha1 string, keys []string, args ...any) *Result
- func (c Conn) EvalShaRO(ctx context.Context, sha1 string, keys []string, args ...any) *Result
- func (c *Conn) Flush() error
- func (c *Conn) Pipeline() Pipeliner
- func (c *Conn) Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]*Result, error)
- func (c *Conn) Receive(ctx context.Context) (any, error)
- func (c *Conn) ReceiveTimeout(timeout time.Duration) (any, error)
- func (c Conn) ScriptExists(ctx context.Context, hashes ...string) *Result
- func (c Conn) ScriptFlush(ctx context.Context) *Result
- func (c Conn) ScriptLoad(ctx context.Context, script string) *Result
- func (c *Conn) Send(commandName string, args ...any) error
- func (c *Conn) TxPipeline() Pipeliner
- func (c *Conn) TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]*Result, error)
- type Message
- type Options
- type Pipeliner
- type Pong
- type PoolStats
- type PubSub
- func (p *PubSub) Channel(opts ...ChannelOption) <-chan *Message
- func (p *PubSub) ChannelWithSubscriptions(opts ...ChannelOption) <-chan any
- func (p *PubSub) Close() error
- func (p *PubSub) PSubscribe(ctx context.Context, patterns ...string) error
- func (p *PubSub) PUnsubscribe(ctx context.Context, patterns ...string) error
- func (p *PubSub) Ping(ctx context.Context, payload ...string) error
- func (p *PubSub) Receive(ctx context.Context) (any, error)
- func (p *PubSub) ReceiveMessage(ctx context.Context) (*Message, error)
- func (p *PubSub) ReceiveTimeout(timeout time.Duration) (any, error)
- func (p *PubSub) String() string
- func (p *PubSub) Subscribe(ctx context.Context, channels ...string) error
- func (p *PubSub) Unsubscribe(ctx context.Context, channels ...string) error
- type Result
- func (r *Result) Bool() (bool, error)
- func (r *Result) Bools() ([]bool, error)
- func (r *Result) ByteSlices() ([][]byte, error)
- func (r *Result) Bytes() ([]byte, error)
- func (r *Result) Err() error
- func (r *Result) Float64() (float64, error)
- func (r *Result) Float64Map() (map[string]float64, error)
- func (r *Result) Float64s() ([]float64, error)
- func (r *Result) Int() (int, error)
- func (r *Result) Int64() (int64, error)
- func (r *Result) Int64Map() (map[string]int64, error)
- func (r *Result) Int64s() ([]int64, error)
- func (r *Result) IntMap() (map[string]int, error)
- func (r *Result) Ints() ([]int, error)
- func (r *Result) Positions() ([]*[2]float64, error)
- func (r *Result) Scan(dest ...any) error
- func (r *Result) ScanSlice(dest any, fieldNames ...string) error
- func (r *Result) ScanStruct(dest any) error
- func (r *Result) String() (string, error)
- func (r *Result) StringMap() (map[string]string, error)
- func (r *Result) Strings() ([]string, error)
- func (r *Result) Uint64() (uint64, error)
- func (r *Result) Uint64Map() (map[string]uint64, error)
- func (r *Result) Uint64s() ([]uint64, error)
- func (r *Result) Val() any
- func (r *Result) Values() ([]any, error)
- type Script
- func (s *Script) Exists(ctx context.Context, c Scripter) *Result
- func (s *Script) Hash() string
- func (s *Script) Load(ctx context.Context, c Scripter) *Result
- func (s *Script) Run(ctx context.Context, c Scripter, keys []string, args ...any) *Result
- func (s *Script) RunRO(ctx context.Context, c Scripter, keys []string, args ...any) *Result
- type Scripter
- type Subscription
- type Tx
Examples ¶
Constants ¶
const ErrClosed = redis.Error("redis: client is closed")
ErrClosed performs any operation on the closed client will return this error.
const ErrNil = redis.Error("redis: nil")
ErrNil reply returned by Redis when key does not exist.
const TxFailedErr = redis.Error("redis: transaction failed")
TxFailedErr transaction redis failed.
Variables ¶
var ErrValuesExhausted = errors.New("redis: values exhausted")
Functions ¶
This section is empty.
Types ¶
type ChannelOption ¶
type ChannelOption interface {
// contains filtered or unexported methods
}
func WithChannelHealthCheckInterval ¶
func WithChannelHealthCheckInterval(d time.Duration) ChannelOption
WithChannelHealthCheckInterval specifies the health check interval. PubSub will ping Redis Server if it does not receive any messages within the interval. To disable health check, use zero interval.
The default is 3 seconds.
func WithChannelSendTimeout ¶
func WithChannelSendTimeout(d time.Duration) ChannelOption
WithChannelSendTimeout specifies the channel send timeout after which the message is dropped.
The default is 60 seconds.
func WithChannelSize ¶
func WithChannelSize(size int) ChannelOption
WithChannelSize specifies the Go chan size that is used to buffer incoming messages.
The default is 100 messages.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is a Redis client representing a pool of zero or more underlying connections. It's safe for concurrent use by multiple goroutines. Client creates and frees connections automatically; it also maintains a free pool of idle connections.
Example ¶
err := rdb.Do(ctx, "SET", "key", "value").Err() if err != nil { panic(err) } val, err := rdb.Do(ctx, "GET", "key").String() if err != nil { panic(err) } fmt.Println("key", val) val2, err := rdb.Do(ctx, "GET", "missing_key").String() switch err { default: panic(err) case redis.ErrNil: fmt.Println("missing_key does not exist") case nil: fmt.Println("missing_key", val2) }
Output: key value missing_key does not exist
func NewClient ¶
NewClient returns a client to the Redis Server specified by Options.
Example ¶
rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", // use default Addr Password: "", // no password set DB: 0, // use default DB }) pong, err := rdb.Do(ctx, "PING").String() fmt.Println(pong, err)
Output: PONG <nil>
func (Client) Close ¶
Close closes the client, releasing any open resources.
It is rare to Close a Client, as the Client is meant to be long-lived and shared between many goroutines.
func (Client) Conn ¶
Conn gets a connection. The application must close the returned connection. This method always returns a valid connection so that applications can defer error handling to the first use of the connection. If there is an error getting an underlying connection, then the connection Err, Do, Send, Flush and Receive methods return that error.
func (Client) Do ¶
Do sends a command to the server and returns the received reply. This function will use the timeout which was set when the connection is created
func (Client) PSubscribe ¶
PSubscribe subscribes the client to the given patterns. Patterns can be omitted to create empty subscription.
func (Client) Pipeline ¶
Example ¶
err := rdb.Do(ctx, "DEL", "pipeline_counter").Err() if err != nil { panic(err) } pipe := rdb.Pipeline() incr := pipe.Send("INCR", "pipeline_counter") pipe.Send("EXPIRE", "pipeline_counter", 1*time.Minute) // Execute // // INCR pipeline_counter // EXPIRE pipeline_counts 60 // // using one rdb-server roundtrip. _, err = pipe.Exec(ctx) if err != nil { panic(err) } fmt.Println(incr.Int())
Output: 1 <nil>
func (Client) Pipelined ¶
Example ¶
err := rdb.Do(ctx, "DEL", "pipelined_counter").Err() if err != nil { panic(err) } var incr *redis.Result _, err = rdb.Pipelined(ctx, func(pipe redis.Pipeliner) error { incr = pipe.Send("INCR", "pipelined_counter") pipe.Send("EXPIRE", "pipelined_counter", 1*time.Minute) return nil }) if err != nil { panic(err) } fmt.Println(incr.Int())
Output: 1 <nil>
func (Client) ScriptExists ¶
func (Client) Subscribe ¶
Subscribe subscribes the client to the specified channels. Channels can be omitted to create empty subscription. Note that this method does not wait on a response from Redis, so the subscription may not be active immediately. To force the connection to wait, you may call the Receive() method on the returned *PubSub like so:
sub := client.Subscribe(queryResp) iface, err := sub.Receive() if err != nil { // handle error } // Should be *Subscription, but others are possible if other actions have been // taken on sub since it was created. switch iface.(type) { case *Subscription: // subscribe succeeded case *Message: // received first message case *Pong: // pong received default: // handle error } ch := sub.Channel()
func (Client) TxPipeline ¶
TxPipeline acts like Pipeline, but wraps queued commands with MULTI/EXEC.
Example ¶
err := rdb.Do(ctx, "DEL", "tx_pipeline_counter").Err() if err != nil { panic(err) } pipe := rdb.TxPipeline() incr := pipe.Send("INCR", "tx_pipeline_counter") pipe.Send("EXPIRE", "tx_pipeline_counter", 1*time.Minute) // Execute // // MULTI // INCR tx_pipeline_counter // EXPIRE tx_pipeline_counter 60 // EXEC // // using one rdb-server roundtrip. _, err = pipe.Exec(ctx) if err != nil { panic(err) } fmt.Println(incr.Int())
Output: 1 <nil>
func (Client) TxPipelined ¶
Example ¶
err := rdb.Do(ctx, "DEL", "tx_pipelined_counter").Err() if err != nil { panic(err) } var incr *redis.Result _, err = rdb.TxPipelined(ctx, func(pipe redis.Pipeliner) error { incr = pipe.Send("INCR", "tx_pipelined_counter") pipe.Send("EXPIRE", "tx_pipelined_counter", 1*time.Minute) return nil }) if err != nil { panic(err) } fmt.Println(incr.Int())
Output: 1 <nil>
func (Client) Watch ¶
Watch prepares a transaction and marks the keys to be watched for conditional execution if there are any keys.
The transaction is automatically closed when fn exits.
Example ¶
// Increment transactionally increments key using GET and SET commands. increment := func(key string) error { // Transactional function. txf := func(tx *redis.Tx) error { // Get current value or zero. n, err := tx.Do(ctx, "GET", key).Int() if err != nil && redis.ErrNil != err { return err } // Actual opperation (local in optimistic lock). n++ // Operation is committed only if the watched keys remain unchanged. _, err = tx.TxPipelined(ctx, func(pipe redis.Pipeliner) error { pipe.Send("SET", key, n) return nil }) return err } const maxRetries = 10000 for i := 0; i < maxRetries; i++ { switch err := rdb.Watch(ctx, txf, key); err { default: // Return any other error. return err case nil: // Success. return nil case redis.ErrNil: // Optimistic lock lost. Retry. } } return errors.New("increment reached maximum number of retries") } err := rdb.Do(ctx, "DEL", "counter3").Err() if err != nil { panic(err) } var wg sync.WaitGroup for i := 0; i < 100; i++ { wg.Add(1) go func() { defer wg.Done() if err := increment("counter3"); err != nil { fmt.Println("increment error:", err) } }() } wg.Wait() n, err := rdb.Do(ctx, "GET", "counter3").Int() fmt.Println("ended with", n, err)
Output: ended with 100 <nil>
type Conn ¶
type Conn struct {
// contains filtered or unexported fields
}
Conn represents a single Redis connection rather than a pool of connections. Prefer running commands from Client unless there is a specific need for a continuous single Redis connection.
Example ¶
conn := rdb.Conn() defer conn.Close() err := conn.Do(ctx, "CLIENT", "SETNAME", "foobar").Err() if err != nil { panic(err) } // Open other connections. for i := 0; i < 10; i++ { go rdb.Do(ctx, "Ping") } s, err := conn.Do(ctx, "CLIENT", "GETNAME").String() if err != nil { panic(err) } fmt.Println(s)
Output: foobar
func (Conn) ScriptExists ¶
func (*Conn) TxPipeline ¶
TxPipeline acts like Pipeline, but wraps queued commands with MULTI/EXEC.
type Options ¶
type Options struct { // The network type, either tcp or unix. // Default is tcp. Network string // host:port address. Addr string // ClientName specifies a client name to be used by the Redis server connection. ClientName string // DialContextFunc specifies a custom dial function with context for creating TCP connections. DialContextFunc func(ctx context.Context, network, addr string) (net.Conn, error) // Username specifies the username to use when connecting to the Redis server when Redis ACLs are used. // Password must also be set otherwise this option will have no effect. Username string // Password specifies the password to use when connecting to the Redis server. Password string // DB specifies the database to select when dialing a connection. DB int // ConnectTimeout specifies the timeout for connecting to the Redis server. // Default is 5 seconds. ConnectTimeout time.Duration // ReadTimeout specifies the timeout for reading a single command reply. // Supported values: // - `0` - default timeout (3 seconds). // - `-1` - no timeout (block indefinitely). // - `-2` - disables SetReadDeadline calls completely. ReadTimeout time.Duration // WriteTimeout specifies the timeout for writing a single command. // Supported values: // - `0` - default timeout (3 seconds). // - `-1` - no timeout (block indefinitely). // - `-2` - disables SetWriteDeadline calls completely. WriteTimeout time.Duration // TLSConfig specifies the config to use when a TLS connection is dialed. TLSConfig *tls.Config // Maximum number of idle connections in the pool. MaxIdle int // Close connections after remaining idle for this duration. If the value // is zero, then idle connections are not closed. Applications should set // the timeout to a value less than the server's timeout. IdleTimeout time.Duration }
Options keeps the settings to set up redis connection.
type Pipeliner ¶
type Pipeliner interface { // Len is to obtain the number of commands in the pipeline that have not yet been executed. Len() int // Send writes the command to the client's output buffer. Send(commandName string, args ...any) *Result // Discard is to discard all commands in the cache that have not yet been executed. Discard() // Exec is to send all the commands buffered in the pipeline to the redis-server. Exec(ctx context.Context) ([]*Result, error) Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]*Result, error) }
Pipeliner is an mechanism to realise Redis Pipeline technique. Pipelining is a technique to extremely speed up processing by packing operations to batches, send them at once to Redis and read a replies in a single step. See https://redis.io/topics/pipelining
type Pong ¶
type Pong struct {
Payload string
}
Pong received as result of a PING command issued by another client.
type PubSub ¶
type PubSub struct {
// contains filtered or unexported fields
}
PubSub implements Pub/Sub commands as described in http://redis.io/topics/pubsub. Message receiving is NOT safe for concurrent use by multiple goroutines.
PubSub automatically reconnects to Redis Server and resubscribes to the channels in case of network errors.
Example ¶
pubsub := rdb.Subscribe(ctx, "mychannel1") // Wait for confirmation that subscription is created before publishing anything. _, err := pubsub.Receive(ctx) if err != nil { panic(err) } // Go channel which receives messages. ch := pubsub.Channel() // Publish a message. err = rdb.Do(ctx, "PUBLISH", "mychannel1", "hello").Err() if err != nil { panic(err) } time.AfterFunc(1*time.Second, func() { // When pubsub is closed channel is closed too. _ = pubsub.Close() }) // Consume messages. for msg := range ch { fmt.Println(msg.Channel, msg.Payload) }
Output: mychannel1 hello
func (*PubSub) Channel ¶
func (p *PubSub) Channel(opts ...ChannelOption) <-chan *Message
Channel returns a Go channel for concurrently receiving messages. The channel is closed together with the PubSub. If the Go channel is blocked full for 30 seconds the message is dropped. Receive* APIs can not be used after channel is created.
go-redis periodically sends ping messages to test connection health and re-subscribes if ping can not not received for 30 seconds.
func (*PubSub) ChannelWithSubscriptions ¶
func (p *PubSub) ChannelWithSubscriptions(opts ...ChannelOption) <-chan any
ChannelWithSubscriptions is like Channel, but message type can be either *Subscription or *Message. Subscription messages can be used to detect reconnections.
ChannelWithSubscriptions can not be used together with Channel.
Example ¶
This example shows how receive pubsub notifications with cancelation.
package main import ( "context" "fmt" "github.com/weiwenchen2022/go-redis" ) // listenPubSubChannels listens for messages on Redis pubsub channels. The // onStart function is called after the channels are subscribed. The onMessage // function is called for each message. func listenPubSubChannels(ctx context.Context, rdb *redis.Client, onStart func() error, onMessage func(channel string, payload string) error, channels ...string, ) error { pubsub := rdb.Subscribe(ctx, channels...) done := make(chan error, 1) // Start a goroutine to receive notifications from the server. go func() { // Go channel which receives messages. ch := pubsub.ChannelWithSubscriptions() // Consume messages. for msgi := range ch { switch msg := msgi.(type) { case *redis.Message: if err := onMessage(msg.Channel, msg.Payload); err != nil { done <- err return } case *redis.Subscription: switch msg.Count { case len(channels): // Notify application when all channels are subscribed. if err := onStart(); err != nil { done <- err return } case 0: // Return from the goroutine when all channels are unsubscribed. done <- nil return } } } }() loop: for { select { case <-ctx.Done(): break loop case err := <-done: // Return error from the receive goroutine. return err } } // Signal the receiving goroutine to exit by unsubscribing from all channels. if err := pubsub.Unsubscribe(ctx); err != nil { return err } // Wait for goroutine to complete. return <-done } func publish(ctx context.Context, rdb *redis.Client) { if err := rdb.Do(ctx, "PUBLISH", "c1", "hello").Err(); err != nil { panic(err) } if err := rdb.Do(ctx, "PUBLISH", "c2", "world").Err(); err != nil { panic(err) } if err := rdb.Do(ctx, "PUBLISH", "c1", "goodbye").Err(); err != nil { panic(err) } } // This example shows how receive pubsub notifications with cancelation. func main() { var ( ctx, cancel = context.WithCancel(context.Background()) rdb = redis.NewClient(&redis.Options{ Addr: "localhost:6379", }) ) err := listenPubSubChannels(ctx, rdb, func() error { // The start callback is a good place to backfill missed // notifications. For the purpose of this example, a goroutine is // started to send notifications. go publish(ctx, rdb) return nil }, func(channel string, payload string) error { fmt.Println("received", payload, "from", channel) // For the purpose of this example, cancel the listener's context // after receiving last message sent by publish(). if payload == "goodbye" { cancel() } return nil }, "c1", "c2") if err != nil { panic(err) } }
Output: received hello from c1 received world from c2 received goodbye from c1
func (*PubSub) PSubscribe ¶
PSubscribe the client to the given patterns. It returns empty subscription if there are no patterns.
func (*PubSub) PUnsubscribe ¶
PUnsubscribe the client from the given patterns, or from all of them if none is given.
func (*PubSub) Receive ¶
Receive returns a message as a Subscription, Message, Pong or error. See PubSub example for details. This is low-level API and in most cases Channel should be used instead.
Example ¶
pubsub := rdb.Subscribe(ctx, "mychannel2") defer pubsub.Close() for i := 0; i < 2; i++ { // ReceiveTimeout is a low level API. Use ReceiveMessage instead. msgi, err := pubsub.ReceiveTimeout(1 * time.Second) if err != nil { panic(err) } switch msg := msgi.(type) { case *redis.Subscription: fmt.Println("subscribed to", msg.Channel) _, err := rdb.Do(ctx, "PUBLISH", "mychannel2", "hello").Int() if err != nil { panic(err) } case *redis.Message: fmt.Println("received", msg.Payload, "from", msg.Channel) default: panic("unreached") } }
Output: subscribed to mychannel2 received hello from mychannel2
func (*PubSub) ReceiveMessage ¶
ReceiveMessage returns a Message or error ignoring Subscription and Pong messages. This is low-level API and in most cases Channel should be used instead.
func (*PubSub) ReceiveTimeout ¶
ReceiveTimeout acts like Receive but returns an error if message is not received in time. This is low-level API and in most cases Channel should be used instead.
type Result ¶
type Result struct {
// contains filtered or unexported fields
}
func (*Result) Bool ¶
Example ¶
err := rdb.Do(ctx, "SET", "foo", 1).Err() if err != nil { panic(err) } exists, err := rdb.Do(ctx, "EXISTS", "foo").Bool() if err != nil { panic(err) } fmt.Printf("%t\n", exists)
Output: true
func (*Result) ByteSlices ¶
func (*Result) Int ¶
Example ¶
err := rdb.Do(ctx, "SET", "k1", 1).Err() if err != nil { panic(err) } n, err := rdb.Do(ctx, "GET", "k1").Int() if err != nil { panic(err) } fmt.Printf("%d\n", n) n, err = rdb.Do(ctx, "INCR", "k1").Int() if err != nil { panic(err) } fmt.Printf("%d\n", n)
Output: 1 2
func (*Result) Ints ¶
Example ¶
err := rdb.Do(ctx, "SADD", "set_with_integers", 4, 5, 6).Err() if err != nil { panic(err) } ints, err := rdb.Do(ctx, "SMEMBERS", "set_with_integers").Ints() if err != nil { panic(err) } fmt.Printf("%v\n", ints)
Output: [4 5 6]
func (*Result) Scan ¶
Example ¶
err := rdb.Do(ctx, "DEL", "album:1", "album:2", "album:3", "albums").Err() if err != nil { panic(err) } if _, err := rdb.Pipelined(ctx, func(pipe redis.Pipeliner) error { pipe.Send("HSET", "album:1", "title", "Red", "rating", 5) pipe.Send("HSET", "album:2", "title", "Earthbound", "rating", 1) pipe.Send("HSET", "album:3", "title", "Beat") pipe.Send("LPUSH", "albums", "1", "2", "3") return nil }); err != nil { panic(err) } res := rdb.Do(ctx, "SORT", "albums", "BY", "album:*->rating", "GET", "album:*->title", "GET", "album:*->rating", ) if err := res.Err(); err != nil { panic(err) } loop: for { var title string rating := -1 // initialize to illegal value to detect nil. err = res.Scan(&title, &rating) switch err { default: panic(err) case redis.ErrValuesExhausted: break loop case nil: } if rating == -1 { fmt.Println(title, "not-rated") } else { fmt.Println(title, rating) } }
Output: Beat not-rated Earthbound 1 Red 5
func (*Result) ScanSlice ¶
Example ¶
err := rdb.Do(ctx, "DEL", "album:1", "album:2", "album:3", "albums").Err() if err != nil { panic(err) } if _, err := rdb.Pipelined(ctx, func(pipe redis.Pipeliner) error { pipe.Send("HSET", "album:1", "title", "Red", "rating", 5) pipe.Send("HSET", "album:2", "title", "Earthbound", "rating", 1) pipe.Send("HSET", "album:3", "title", "Beat", "rating", 4) pipe.Send("LPUSH", "albums", "1", "2", "3") return nil }); err != nil { panic(err) } res := rdb.Do(ctx, "SORT", "albums", "BY", "album:*->rating", "GET", "album:*->title", "GET", "album:*->rating", ) if err := res.Err(); err != nil { panic(err) } var albums []struct { Title string Rating int } if err := res.ScanSlice(&albums); err != nil { panic(err) } fmt.Printf("%v\n", albums)
Output: [{Earthbound 1} {Beat 4} {Red 5}]
func (*Result) ScanStruct ¶
Example ¶
err := rdb.Do(ctx, "DEL", "album:1").Err() if err != nil { panic(err) } if err := rdb.Do(ctx, "HSET", "album:1", "title", "Electric Ladyland", "artist", "Jimi Hendrix", "price", 4.95, "likes", 8, ).Err(); err != nil { panic(err) } res := rdb.Do(ctx, "HGETALL", "album:1") if err := res.Err(); err != nil { panic(err) } type Album struct { Title string `redis:"title"` Artist string `redis:"artist"` Price float64 `redis:"price"` Likes int `redis:"likes"` } ab := new(Album) if err := res.ScanStruct(ab); err != nil { panic(err) } fmt.Printf("%+v\n", ab)
Output: &{Title:Electric Ladyland Artist:Jimi Hendrix Price:4.95 Likes:8}
type Script ¶
type Script struct {
// contains filtered or unexported fields
}
Script encapsulates the source and hash for a Lua script.
Example ¶
incrByXX := redis.NewScript(` if not redis.call("GET", KEYS[1]) then return false end return redis.call("INCRBY", KEYS[1], ARGV[1]) `) if err := rdb.Do(ctx, "DEL", "xx_counter").Err(); err != nil { panic(err) } n, err := incrByXX.Run(ctx, rdb, []string{"xx_counter"}, 2).Int() fmt.Println(n, err) err = rdb.Do(ctx, "SET", "xx_counter", "40").Err() if err != nil { panic(err) } n, err = incrByXX.Run(ctx, rdb, []string{"xx_counter"}, 2).Int() fmt.Println(n, err)
Output: 0 redis: nil 42 <nil>
type Scripter ¶
type Scripter interface { Eval(ctx context.Context, script string, keys []string, args ...any) *Result EvalSha(ctx context.Context, sha1 string, keys []string, args ...any) *Result EvalRO(ctx context.Context, script string, keys []string, args ...any) *Result EvalShaRO(ctx context.Context, sha1 string, keys []string, args ...any) *Result ScriptExists(ctx context.Context, hashes ...string) *Result ScriptLoad(ctx context.Context, script string) *Result }
type Subscription ¶
type Subscription struct { // Can be "subscribe", "unsubscribe", "psubscribe" or "punsubscribe". Kind string // Channel name we have subscribed to. Channel string // Number of channels we are currently subscribed to. Count int }
Subscription received after a successful subscription to channel.
func (*Subscription) String ¶
func (s *Subscription) String() string
type Tx ¶
type Tx struct {
*Conn
}
Tx implements Redis transactions as described in http://redis.io/topics/transactions. It's NOT safe for concurrent use by multiple goroutines, because Exec resets list of watched keys.
If you don't need WATCH, use Pipeline instead.