Skip to content

Commit 68d8c59

Browse files
authored
chore(release): v9.17.1 (#3617)
* add release notes * update version to 9.17.1
1 parent 932caa5 commit 68d8c59

File tree

18 files changed

+309
-17
lines changed

18 files changed

+309
-17
lines changed

RELEASE-NOTES.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,27 @@
11
# Release Notes
22

3+
# 9.17.1 (2025-11-25)
4+
5+
## 🐛 Bug Fixes
6+
7+
- add wait to keyless commands list ([#3615](https://github.com/redis/go-redis/pull/3615)) by [@marcoferrer](https://github.com/marcoferrer)
8+
- fix(time): remove cached time optimization ([#3611](https://github.com/redis/go-redis/pull/3611)) by [@ndyakov](https://github.com/ndyakov)
9+
10+
## 🧰 Maintenance
11+
12+
- chore(deps): bump golangci/golangci-lint-action from 9.0.0 to 9.1.0 ([#3609](https://github.com/redis/go-redis/pull/3609))
13+
- chore(deps): bump actions/checkout from 5 to 6 ([#3610](https://github.com/redis/go-redis/pull/3610))
14+
- chore(script): fix help call in tag.sh ([#3606](https://github.com/redis/go-redis/pull/3606)) by [@ndyakov](https://github.com/ndyakov)
15+
16+
## Contributors
17+
We'd like to thank all the contributors who worked on this release!
18+
19+
[@marcoferrer](https://github.com/marcoferrer) and [@ndyakov](https://github.com/ndyakov)
20+
21+
---
22+
23+
**Full Changelog**: https://github.com/redis/go-redis/compare/v9.17.0...v9.17.1
24+
325
# 9.17.0 (2025-11-19)
426

527
## 🚀 Highlights

example/cluster-mget/README.md

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# Redis Cluster MGET Example
2+
3+
This example demonstrates how to use the Redis Cluster client with the `MGET` command to retrieve multiple keys efficiently.
4+
5+
## Overview
6+
7+
The example shows:
8+
- Creating a Redis Cluster client
9+
- Setting 10 keys with individual `SET` commands
10+
- Retrieving all 10 keys in a single operation using `MGET`
11+
- Validating that the retrieved values match the expected values
12+
- Cleaning up by deleting the test keys
13+
14+
## Prerequisites
15+
16+
You need a running Redis Cluster. The example expects cluster nodes at:
17+
- `localhost:7000`
18+
- `localhost:7001`
19+
- `localhost:7002`
20+
21+
### Setting up a Redis Cluster (using Docker)
22+
23+
If you don't have a Redis Cluster running, you can use the docker-compose setup from the repository root:
24+
25+
```bash
26+
# From the go-redis repository root
27+
docker compose --profile cluster up -d
28+
```
29+
30+
This will start a Redis Cluster with nodes on ports 16600-16605.
31+
32+
If using the docker-compose cluster, update the `Addrs` in `main.go` to:
33+
```go
34+
Addrs: []string{
35+
"localhost:16600",
36+
"localhost:16601",
37+
"localhost:16602",
38+
},
39+
```
40+
41+
## Running the Example
42+
43+
```bash
44+
go run main.go
45+
```
46+
47+
## Expected Output
48+
49+
```
50+
✓ Connected to Redis cluster
51+
52+
=== Setting 10 keys ===
53+
✓ SET key0 = value0
54+
✓ SET key1 = value1
55+
✓ SET key2 = value2
56+
✓ SET key3 = value3
57+
✓ SET key4 = value4
58+
✓ SET key5 = value5
59+
✓ SET key6 = value6
60+
✓ SET key7 = value7
61+
✓ SET key8 = value8
62+
✓ SET key9 = value9
63+
64+
=== Retrieving keys with MGET ===
65+
66+
=== Validating MGET results ===
67+
✓ key0: value0
68+
✓ key1: value1
69+
✓ key2: value2
70+
✓ key3: value3
71+
✓ key4: value4
72+
✓ key5: value5
73+
✓ key6: value6
74+
✓ key7: value7
75+
✓ key8: value8
76+
✓ key9: value9
77+
78+
=== Summary ===
79+
✓ All values retrieved successfully and match expected values!
80+
81+
=== Cleaning up ===
82+
✓ Cleanup complete
83+
```
84+
85+
## Key Concepts
86+
87+
### MGET Command
88+
89+
`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.
90+
91+
**Syntax:**
92+
```go
93+
result, err := rdb.MGet(ctx, key1, key2, key3, ...).Result()
94+
```
95+
96+
**Returns:**
97+
- A slice of `interface{}` values
98+
- Each value corresponds to a key in the same order
99+
- `nil` is returned for keys that don't exist
100+
101+
### Cluster Client
102+
103+
The `ClusterClient` automatically handles:
104+
- Distributing keys across cluster nodes based on hash slots
105+
- Following cluster redirects
106+
- Maintaining connections to all cluster nodes
107+
- Retrying operations on cluster topology changes
108+
109+
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.
110+
111+
## Code Highlights
112+
113+
```go
114+
// Create cluster client
115+
rdb := redis.NewClusterClient(&redis.ClusterOptions{
116+
Addrs: []string{
117+
"localhost:7000",
118+
"localhost:7001",
119+
"localhost:7002",
120+
},
121+
})
122+
123+
// Set individual keys
124+
for i := 0; i < 10; i++ {
125+
err := rdb.Set(ctx, fmt.Sprintf("key%d", i), fmt.Sprintf("value%d", i), 0).Err()
126+
// handle error
127+
}
128+
129+
// Retrieve all keys with MGET
130+
result, err := rdb.MGet(ctx, keys...).Result()
131+
132+
// Validate results
133+
for i, val := range result {
134+
actualValue, ok := val.(string)
135+
// validate actualValue matches expected
136+
}
137+
```
138+
139+
## Learn More
140+
141+
- [Redis MGET Documentation](https://redis.io/commands/mget/)
142+
- [Redis Cluster Specification](https://redis.io/topics/cluster-spec)
143+
- [go-redis Documentation](https://redis.uptrace.dev/)
144+

example/cluster-mget/go.mod

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module github.com/redis/go-redis/example/cluster-mget
2+
3+
go 1.18
4+
5+
replace github.com/redis/go-redis/v9 => ../..
6+
7+
require github.com/redis/go-redis/v9 v9.16.0
8+
9+
require (
10+
github.com/cespare/xxhash/v2 v2.3.0 // indirect
11+
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
12+
)

example/cluster-mget/go.sum

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
2+
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
3+
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
4+
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
5+
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
6+
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=

example/cluster-mget/main.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/redis/go-redis/v9"
8+
)
9+
10+
func main() {
11+
ctx := context.Background()
12+
13+
// Create a cluster client
14+
rdb := redis.NewClusterClient(&redis.ClusterOptions{
15+
Addrs: []string{
16+
"localhost:16600",
17+
"localhost:16601",
18+
"localhost:16602",
19+
"localhost:16603",
20+
"localhost:16604",
21+
"localhost:16605",
22+
},
23+
})
24+
defer rdb.Close()
25+
26+
// Test connection
27+
if err := rdb.Ping(ctx).Err(); err != nil {
28+
panic(fmt.Sprintf("Failed to connect to Redis cluster: %v", err))
29+
}
30+
31+
fmt.Println("✓ Connected to Redis cluster")
32+
33+
// Define 10 keys and values
34+
keys := make([]string, 10)
35+
values := make([]string, 10)
36+
for i := 0; i < 10; i++ {
37+
keys[i] = fmt.Sprintf("key%d", i)
38+
values[i] = fmt.Sprintf("value%d", i)
39+
}
40+
41+
// Set all 10 keys
42+
fmt.Println("\n=== Setting 10 keys ===")
43+
for i := 0; i < 10; i++ {
44+
err := rdb.Set(ctx, keys[i], values[i], 0).Err()
45+
if err != nil {
46+
panic(fmt.Sprintf("Failed to set %s: %v", keys[i], err))
47+
}
48+
fmt.Printf("✓ SET %s = %s\n", keys[i], values[i])
49+
}
50+
51+
/*
52+
// Retrieve all keys using MGET
53+
fmt.Println("\n=== Retrieving keys with MGET ===")
54+
result, err := rdb.MGet(ctx, keys...).Result()
55+
if err != nil {
56+
panic(fmt.Sprintf("Failed to execute MGET: %v", err))
57+
}
58+
*/
59+
60+
/*
61+
// Validate the results
62+
fmt.Println("\n=== Validating MGET results ===")
63+
allValid := true
64+
for i, val := range result {
65+
expectedValue := values[i]
66+
actualValue, ok := val.(string)
67+
68+
if !ok {
69+
fmt.Printf("✗ %s: expected string, got %T\n", keys[i], val)
70+
allValid = false
71+
continue
72+
}
73+
74+
if actualValue != expectedValue {
75+
fmt.Printf("✗ %s: expected '%s', got '%s'\n", keys[i], expectedValue, actualValue)
76+
allValid = false
77+
} else {
78+
fmt.Printf("✓ %s: %s\n", keys[i], actualValue)
79+
}
80+
}
81+
82+
// Print summary
83+
fmt.Println("\n=== Summary ===")
84+
if allValid {
85+
fmt.Println("✓ All values retrieved successfully and match expected values!")
86+
} else {
87+
fmt.Println("✗ Some values did not match expected values")
88+
}
89+
*/
90+
91+
// Clean up - delete the keys
92+
fmt.Println("\n=== Cleaning up ===")
93+
for _, key := range keys {
94+
if err := rdb.Del(ctx, key).Err(); err != nil {
95+
fmt.Printf("Warning: Failed to delete %s: %v\n", key, err)
96+
}
97+
}
98+
fmt.Println("✓ Cleanup complete")
99+
100+
err := rdb.Set(ctx, "{tag}exists", "asdf",0).Err()
101+
if err != nil {
102+
panic(err)
103+
}
104+
val, err := rdb.Get(ctx, "{tag}nilkeykey1").Result()
105+
fmt.Printf("\nval: %+v err: %+v\n", val, err)
106+
valm, err := rdb.MGet(ctx, "{tag}nilkeykey1", "{tag}exists").Result()
107+
fmt.Printf("\nval: %+v err: %+v\n", valm, err)
108+
}

example/del-keys-without-ttl/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ go 1.18
55
replace github.com/redis/go-redis/v9 => ../..
66

77
require (
8-
github.com/redis/go-redis/v9 v9.17.0
8+
github.com/redis/go-redis/v9 v9.17.1
99
go.uber.org/zap v1.24.0
1010
)
1111

example/digest-optimistic-locking/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ go 1.18
55
replace github.com/redis/go-redis/v9 => ../..
66

77
require (
8-
github.com/redis/go-redis/v9 v9.17.0
8+
github.com/redis/go-redis/v9 v9.17.1
99
github.com/zeebo/xxh3 v1.0.2
1010
)
1111

example/hll/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ go 1.18
44

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

7-
require github.com/redis/go-redis/v9 v9.17.0
7+
require github.com/redis/go-redis/v9 v9.17.1
88

99
require (
1010
github.com/cespare/xxhash/v2 v2.3.0 // indirect

example/hset-struct/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ replace github.com/redis/go-redis/v9 => ../..
66

77
require (
88
github.com/davecgh/go-spew v1.1.1
9-
github.com/redis/go-redis/v9 v9.17.0
9+
github.com/redis/go-redis/v9 v9.17.1
1010
)
1111

1212
require (

example/lua-scripting/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ go 1.18
44

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

7-
require github.com/redis/go-redis/v9 v9.17.0
7+
require github.com/redis/go-redis/v9 v9.17.1
88

99
require (
1010
github.com/cespare/xxhash/v2 v2.3.0 // indirect

0 commit comments

Comments
 (0)