Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
# Release Notes

# 9.17.1 (2025-11-25)

## 🐛 Bug Fixes

- add wait to keyless commands list ([#3615](https://github.com/redis/go-redis/pull/3615)) by [@marcoferrer](https://github.com/marcoferrer)
- fix(time): remove cached time optimization ([#3611](https://github.com/redis/go-redis/pull/3611)) by [@ndyakov](https://github.com/ndyakov)

## 🧰 Maintenance

- chore(deps): bump golangci/golangci-lint-action from 9.0.0 to 9.1.0 ([#3609](https://github.com/redis/go-redis/pull/3609))
- chore(deps): bump actions/checkout from 5 to 6 ([#3610](https://github.com/redis/go-redis/pull/3610))
- chore(script): fix help call in tag.sh ([#3606](https://github.com/redis/go-redis/pull/3606)) by [@ndyakov](https://github.com/ndyakov)

## Contributors
We'd like to thank all the contributors who worked on this release!

[@marcoferrer](https://github.com/marcoferrer) and [@ndyakov](https://github.com/ndyakov)

---

**Full Changelog**: https://github.com/redis/go-redis/compare/v9.17.0...v9.17.1

# 9.17.0 (2025-11-19)

## 🚀 Highlights
Expand Down
144 changes: 144 additions & 0 deletions example/cluster-mget/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# Redis Cluster MGET Example

This example demonstrates how to use the Redis Cluster client with the `MGET` command to retrieve multiple keys efficiently.

## Overview

The example shows:
- Creating a Redis Cluster client
- Setting 10 keys with individual `SET` commands
- Retrieving all 10 keys in a single operation using `MGET`
- Validating that the retrieved values match the expected values
- Cleaning up by deleting the test keys

## Prerequisites

You need a running Redis Cluster. The example expects cluster nodes at:
- `localhost:7000`
- `localhost:7001`
- `localhost:7002`

### Setting up a Redis Cluster (using Docker)

If you don't have a Redis Cluster running, you can use the docker-compose setup from the repository root:

```bash
# From the go-redis repository root
docker compose --profile cluster up -d
```

This will start a Redis Cluster with nodes on ports 16600-16605.

If using the docker-compose cluster, update the `Addrs` in `main.go` to:
```go
Addrs: []string{
"localhost:16600",
"localhost:16601",
"localhost:16602",
},
```

## Running the Example

```bash
go run main.go
```

## Expected Output

```
✓ Connected to Redis cluster

=== Setting 10 keys ===
✓ SET key0 = value0
✓ SET key1 = value1
✓ SET key2 = value2
✓ SET key3 = value3
✓ SET key4 = value4
✓ SET key5 = value5
✓ SET key6 = value6
✓ SET key7 = value7
✓ SET key8 = value8
✓ SET key9 = value9

=== Retrieving keys with MGET ===

=== Validating MGET results ===
✓ key0: value0
✓ key1: value1
✓ key2: value2
✓ key3: value3
✓ key4: value4
✓ key5: value5
✓ key6: value6
✓ key7: value7
✓ key8: value8
✓ key9: value9

=== Summary ===
✓ All values retrieved successfully and match expected values!

=== Cleaning up ===
✓ Cleanup complete
```

## Key Concepts

### MGET Command

`MGET` (Multiple GET) is a Redis command that retrieves the values of multiple keys in a single operation. This is more efficient than executing multiple individual `GET` commands.

**Syntax:**
```go
result, err := rdb.MGet(ctx, key1, key2, key3, ...).Result()
```

**Returns:**
- A slice of `interface{}` values
- Each value corresponds to a key in the same order
- `nil` is returned for keys that don't exist

### Cluster Client

The `ClusterClient` automatically handles:
- Distributing keys across cluster nodes based on hash slots
- Following cluster redirects
- Maintaining connections to all cluster nodes
- Retrying operations on cluster topology changes

For `MGET` operations in a cluster, the client may need to split the request across multiple nodes if the keys map to different hash slots.

## Code Highlights

```go
// Create cluster client
rdb := redis.NewClusterClient(&redis.ClusterOptions{
Addrs: []string{
"localhost:7000",
"localhost:7001",
"localhost:7002",
},
})

// Set individual keys
for i := 0; i < 10; i++ {
err := rdb.Set(ctx, fmt.Sprintf("key%d", i), fmt.Sprintf("value%d", i), 0).Err()
// handle error
}

// Retrieve all keys with MGET
result, err := rdb.MGet(ctx, keys...).Result()

// Validate results
for i, val := range result {
actualValue, ok := val.(string)
// validate actualValue matches expected
}
```

## Learn More

- [Redis MGET Documentation](https://redis.io/commands/mget/)
- [Redis Cluster Specification](https://redis.io/topics/cluster-spec)
- [go-redis Documentation](https://redis.uptrace.dev/)

12 changes: 12 additions & 0 deletions example/cluster-mget/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module github.com/redis/go-redis/example/cluster-mget

go 1.18

replace github.com/redis/go-redis/v9 => ../..

require github.com/redis/go-redis/v9 v9.16.0

require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
)
6 changes: 6 additions & 0 deletions example/cluster-mget/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
108 changes: 108 additions & 0 deletions example/cluster-mget/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package main

import (
"context"
"fmt"

"github.com/redis/go-redis/v9"
)

func main() {
ctx := context.Background()

// Create a cluster client
rdb := redis.NewClusterClient(&redis.ClusterOptions{
Addrs: []string{
"localhost:16600",
"localhost:16601",
"localhost:16602",
"localhost:16603",
"localhost:16604",
"localhost:16605",
},
})
defer rdb.Close()

// Test connection
if err := rdb.Ping(ctx).Err(); err != nil {
panic(fmt.Sprintf("Failed to connect to Redis cluster: %v", err))
}

fmt.Println("✓ Connected to Redis cluster")

// Define 10 keys and values
keys := make([]string, 10)
values := make([]string, 10)
for i := 0; i < 10; i++ {
keys[i] = fmt.Sprintf("key%d", i)
values[i] = fmt.Sprintf("value%d", i)
}

// Set all 10 keys
fmt.Println("\n=== Setting 10 keys ===")
for i := 0; i < 10; i++ {
err := rdb.Set(ctx, keys[i], values[i], 0).Err()
if err != nil {
panic(fmt.Sprintf("Failed to set %s: %v", keys[i], err))
}
fmt.Printf("✓ SET %s = %s\n", keys[i], values[i])
}

/*
// Retrieve all keys using MGET
fmt.Println("\n=== Retrieving keys with MGET ===")
result, err := rdb.MGet(ctx, keys...).Result()
if err != nil {
panic(fmt.Sprintf("Failed to execute MGET: %v", err))
}
*/

/*
// Validate the results
fmt.Println("\n=== Validating MGET results ===")
allValid := true
for i, val := range result {
expectedValue := values[i]
actualValue, ok := val.(string)

if !ok {
fmt.Printf("✗ %s: expected string, got %T\n", keys[i], val)
allValid = false
continue
}

if actualValue != expectedValue {
fmt.Printf("✗ %s: expected '%s', got '%s'\n", keys[i], expectedValue, actualValue)
allValid = false
} else {
fmt.Printf("✓ %s: %s\n", keys[i], actualValue)
}
}

// Print summary
fmt.Println("\n=== Summary ===")
if allValid {
fmt.Println("✓ All values retrieved successfully and match expected values!")
} else {
fmt.Println("✗ Some values did not match expected values")
}
*/

// Clean up - delete the keys
fmt.Println("\n=== Cleaning up ===")
for _, key := range keys {
if err := rdb.Del(ctx, key).Err(); err != nil {
fmt.Printf("Warning: Failed to delete %s: %v\n", key, err)
}
}
fmt.Println("✓ Cleanup complete")

err := rdb.Set(ctx, "{tag}exists", "asdf",0).Err()
if err != nil {
panic(err)
}
val, err := rdb.Get(ctx, "{tag}nilkeykey1").Result()
fmt.Printf("\nval: %+v err: %+v\n", val, err)
valm, err := rdb.MGet(ctx, "{tag}nilkeykey1", "{tag}exists").Result()
fmt.Printf("\nval: %+v err: %+v\n", valm, err)
}
2 changes: 1 addition & 1 deletion example/del-keys-without-ttl/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.18
replace github.com/redis/go-redis/v9 => ../..

require (
github.com/redis/go-redis/v9 v9.17.0
github.com/redis/go-redis/v9 v9.17.1
go.uber.org/zap v1.24.0
)

Expand Down
2 changes: 1 addition & 1 deletion example/digest-optimistic-locking/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.18
replace github.com/redis/go-redis/v9 => ../..

require (
github.com/redis/go-redis/v9 v9.17.0
github.com/redis/go-redis/v9 v9.17.1
github.com/zeebo/xxh3 v1.0.2
)

Expand Down
2 changes: 1 addition & 1 deletion example/hll/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.18

replace github.com/redis/go-redis/v9 => ../..

require github.com/redis/go-redis/v9 v9.17.0
require github.com/redis/go-redis/v9 v9.17.1

require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect
Expand Down
2 changes: 1 addition & 1 deletion example/hset-struct/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ replace github.com/redis/go-redis/v9 => ../..

require (
github.com/davecgh/go-spew v1.1.1
github.com/redis/go-redis/v9 v9.17.0
github.com/redis/go-redis/v9 v9.17.1
)

require (
Expand Down
2 changes: 1 addition & 1 deletion example/lua-scripting/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.18

replace github.com/redis/go-redis/v9 => ../..

require github.com/redis/go-redis/v9 v9.17.0
require github.com/redis/go-redis/v9 v9.17.1

require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect
Expand Down
6 changes: 3 additions & 3 deletions example/otel/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ replace github.com/redis/go-redis/extra/redisotel/v9 => ../../extra/redisotel
replace github.com/redis/go-redis/extra/rediscmd/v9 => ../../extra/rediscmd

require (
github.com/redis/go-redis/extra/redisotel/v9 v9.17.0
github.com/redis/go-redis/v9 v9.17.0
github.com/redis/go-redis/extra/redisotel/v9 v9.17.1
github.com/redis/go-redis/v9 v9.17.1
github.com/uptrace/uptrace-go v1.21.0
go.opentelemetry.io/otel v1.22.0
)
Expand All @@ -25,7 +25,7 @@ require (
github.com/go-logr/stdr v1.2.2 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect
github.com/redis/go-redis/extra/rediscmd/v9 v9.17.0 // indirect
github.com/redis/go-redis/extra/rediscmd/v9 v9.17.1 // indirect
go.opentelemetry.io/contrib/instrumentation/runtime v0.46.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect
Expand Down
2 changes: 1 addition & 1 deletion example/redis-bloom/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.18

replace github.com/redis/go-redis/v9 => ../..

require github.com/redis/go-redis/v9 v9.17.0
require github.com/redis/go-redis/v9 v9.17.1

require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect
Expand Down
2 changes: 1 addition & 1 deletion example/scan-struct/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ replace github.com/redis/go-redis/v9 => ../..

require (
github.com/davecgh/go-spew v1.1.1
github.com/redis/go-redis/v9 v9.17.0
github.com/redis/go-redis/v9 v9.17.1
)

require (
Expand Down
4 changes: 2 additions & 2 deletions extra/rediscensus/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ replace github.com/redis/go-redis/v9 => ../..
replace github.com/redis/go-redis/extra/rediscmd/v9 => ../rediscmd

require (
github.com/redis/go-redis/extra/rediscmd/v9 v9.17.0
github.com/redis/go-redis/v9 v9.17.0
github.com/redis/go-redis/extra/rediscmd/v9 v9.17.1
github.com/redis/go-redis/v9 v9.17.1
go.opencensus.io v0.24.0
)

Expand Down
Loading
Loading