1
0
mirror of https://github.com/redis/go-redis.git synced 2025-12-02 06:22:31 +03:00

Merge branch 'master' into ndyakov/optional-logger

This commit is contained in:
Nedyalko Dyakov
2025-11-26 12:32:25 +02:00
committed by GitHub
19 changed files with 311 additions and 19 deletions

View File

@@ -20,7 +20,7 @@ jobs:
steps:
# First step: Handle regular issues (excluding needs-information)
- name: Mark regular issues as stale
uses: actions/stale@v9
uses: actions/stale@v10
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
@@ -64,7 +64,7 @@ jobs:
# Second step: Handle needs-information issues with accelerated timeline
- name: Mark needs-information issues as stale
uses: actions/stale@v9
uses: actions/stale@v10
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -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

View File

@@ -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/)

View File

@@ -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
)

View File

@@ -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=

View File

@@ -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)
}

View File

@@ -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
)

View File

@@ -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
)

View File

@@ -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

View File

@@ -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 (

View File

@@ -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

View File

@@ -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
)
@@ -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

View File

@@ -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

View File

@@ -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 (

View File

@@ -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
)

View File

@@ -7,7 +7,7 @@ replace github.com/redis/go-redis/v9 => ../..
require (
github.com/bsm/ginkgo/v2 v2.12.0
github.com/bsm/gomega v1.27.10
github.com/redis/go-redis/v9 v9.17.0
github.com/redis/go-redis/v9 v9.17.1
)
require (

View File

@@ -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.opentelemetry.io/otel v1.22.0
go.opentelemetry.io/otel/metric v1.22.0
go.opentelemetry.io/otel/sdk v1.22.0

View File

@@ -6,7 +6,7 @@ replace github.com/redis/go-redis/v9 => ../..
require (
github.com/prometheus/client_golang v1.14.0
github.com/redis/go-redis/v9 v9.17.0
github.com/redis/go-redis/v9 v9.17.1
)
require (

View File

@@ -2,5 +2,5 @@ package redis
// Version is the current release version.
func Version() string {
return "9.17.0"
return "9.17.1"
}