Skip to content

Commit 30e4fe4

Browse files
authored
Merge branch 'master' into load-balance-search-commands-to-shards
2 parents a98b643 + 5b0b228 commit 30e4fe4

File tree

34 files changed

+2359
-130
lines changed

34 files changed

+2359
-130
lines changed

.github/RELEASE_NOTES_TEMPLATE.md

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# Release Notes Template for go-redis
2+
3+
This template provides a structured format for creating release notes for go-redis releases.
4+
5+
## Format Structure
6+
7+
```markdown
8+
# X.Y.Z (YYYY-MM-DD)
9+
10+
## 🚀 Highlights
11+
12+
### [Category Name]
13+
Brief description of the major feature/change with context and impact.
14+
- Key points
15+
- Performance metrics if applicable
16+
- Links to documentation
17+
18+
### [Another Category]
19+
...
20+
21+
## ✨ New Features
22+
23+
- Feature description ([#XXXX](https://github.com/redis/go-redis/pull/XXXX)) by [@username](https://github.com/username)
24+
- ...
25+
26+
## 🐛 Bug Fixes
27+
28+
- Fix description ([#XXXX](https://github.com/redis/go-redis/pull/XXXX)) by [@username](https://github.com/username)
29+
- ...
30+
31+
## ⚡ Performance
32+
33+
- Performance improvement description ([#XXXX](https://github.com/redis/go-redis/pull/XXXX)) by [@username](https://github.com/username)
34+
- ...
35+
36+
## 🧪 Testing & Infrastructure
37+
38+
- Testing/CI improvement ([#XXXX](https://github.com/redis/go-redis/pull/XXXX)) by [@username](https://github.com/username)
39+
- ...
40+
41+
## 👥 Contributors
42+
43+
We'd like to thank all the contributors who worked on this release!
44+
45+
[@username1](https://github.com/username1), [@username2](https://github.com/username2), ...
46+
47+
---
48+
49+
**Full Changelog**: https://github.com/redis/go-redis/compare/vX.Y-1.Z...vX.Y.Z
50+
```
51+
52+
## Guidelines
53+
54+
### Highlights Section
55+
The Highlights section should contain the **most important** user-facing changes. Common categories include:
56+
57+
- **Typed Errors** - Error handling improvements
58+
- **New Commands** - New Redis commands support (especially for new Redis versions)
59+
- **Search & Vector** - RediSearch and vector-related features
60+
- **Connection Pool** - Pool improvements and performance
61+
- **Metrics & Observability** - Monitoring and instrumentation
62+
- **Breaking Changes** - Any breaking changes (should be prominent)
63+
64+
Each highlight should:
65+
- Have a descriptive title
66+
- Include context about why it matters
67+
- Link to relevant PRs
68+
- Include performance metrics if applicable
69+
70+
### New Features Section
71+
- List all new features with PR links and contributor attribution
72+
- Use descriptive text, not just PR titles
73+
- Group related features together if it makes sense
74+
75+
### Bug Fixes Section
76+
- Only include actual bug fixes
77+
- Be specific about what was broken and how it's fixed
78+
- Include issue links if the PR references an issue
79+
80+
### Performance Section
81+
- Separate from New Features to highlight performance work
82+
- Include metrics when available (e.g., "47-67% faster", "33% less memory")
83+
- Explain the impact on users
84+
85+
### Testing & Infrastructure Section
86+
- Include only important testing/CI changes
87+
- **Exclude** dependency bumps (e.g., dependabot PRs for actions)
88+
- **Exclude** minor CI tweaks unless they're significant
89+
- Include major Redis version updates in CI
90+
91+
### What to Exclude
92+
- Dependency bumps (dependabot PRs)
93+
- Minor documentation typo fixes
94+
- Internal refactoring that doesn't affect users
95+
- Duplicate entries (same PR in multiple sections)
96+
- `dependabot[bot]` from contributors list
97+
98+
### Formatting Rules
99+
1. **PR Links**: Use `([#XXXX](https://github.com/redis/go-redis/pull/XXXX))` format
100+
2. **Contributor Links**: Use `[@username](https://github.com/username)` format
101+
3. **Issue Links**: Use `([#XXXX](https://github.com/redis/go-redis/issues/XXXX))` format
102+
4. **Full Changelog**: Always include at the bottom with correct version comparison
103+
104+
### Getting PR Information
105+
Use GitHub API to fetch PR details:
106+
```bash
107+
# Get recent merged PRs
108+
gh pr list --state merged --limit 50 --json number,title,author,mergedAt,url
109+
```
110+
111+
Or use the GitHub web interface to review merged PRs between releases.
112+
113+
### Example Workflow
114+
1. Gather all merged PRs since last release
115+
2. Categorize PRs by type (feature, bug fix, performance, etc.)
116+
3. Identify the 3-5 most important changes for Highlights
117+
4. Remove duplicates and dependency bumps
118+
5. Add PR and contributor links
119+
6. Review for clarity and completeness
120+
7. Add Full Changelog link with correct version tags
121+
122+
## Example (v9.17.0)
123+
124+
See the v9.17.0 release notes in `RELEASE-NOTES.md` for a complete example following this template.
125+

.github/actions/run-tests/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ runs:
2424
2525
# Mapping of redis version to redis testing containers
2626
declare -A redis_version_mapping=(
27-
["8.4.x"]="8.4-RC1-pre.2"
27+
["8.4.x"]="8.4.0"
2828
["8.2.x"]="8.2.1-pre"
2929
["8.0.x"]="8.0.2"
3030
)

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ jobs:
4444
4545
# Mapping of redis version to redis testing containers
4646
declare -A redis_version_mapping=(
47-
["8.4.x"]="8.4-RC1-pre.2"
47+
["8.4.x"]="8.4.0"
4848
["8.2.x"]="8.2.1-pre"
4949
["8.0.x"]="8.0.2"
5050
)

.github/workflows/doctests.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616

1717
services:
1818
redis-stack:
19-
image: redislabs/client-libs-test:8.4-RC1-pre.2
19+
image: redislabs/client-libs-test:8.4.0
2020
env:
2121
TLS_ENABLED: no
2222
REDIS_CLUSTER: no

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ GO_MOD_DIRS := $(shell find . -type f -name 'go.mod' -exec dirname {} \; | sort)
22
REDIS_VERSION ?= 8.4
33
RE_CLUSTER ?= false
44
RCE_DOCKER ?= true
5-
CLIENT_LIBS_TEST_IMAGE ?= redislabs/client-libs-test:8.4-RC1-pre.2
5+
CLIENT_LIBS_TEST_IMAGE ?= redislabs/client-libs-test:8.4.0
66

77
docker.start:
88
export RE_CLUSTER=$(RE_CLUSTER) && \

README.md

Lines changed: 149 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
[![build workflow](https://github.com/redis/go-redis/actions/workflows/build.yml/badge.svg)](https://github.com/redis/go-redis/actions)
44
[![PkgGoDev](https://pkg.go.dev/badge/github.com/redis/go-redis/v9)](https://pkg.go.dev/github.com/redis/go-redis/v9?tab=doc)
5-
[![Documentation](https://img.shields.io/badge/redis-documentation-informational)](https://redis.uptrace.dev/)
5+
[![Documentation](https://img.shields.io/badge/redis-documentation-informational)](https://redis.io/docs/latest/develop/clients/go/)
66
[![Go Report Card](https://goreportcard.com/badge/github.com/redis/go-redis/v9)](https://goreportcard.com/report/github.com/redis/go-redis/v9)
77
[![codecov](https://codecov.io/github/redis/go-redis/graph/badge.svg?token=tsrCZKuSSw)](https://codecov.io/github/redis/go-redis)
88

@@ -17,15 +17,15 @@
1717
## Supported versions
1818

1919
In `go-redis` we are aiming to support the last three releases of Redis. Currently, this means we do support:
20-
- [Redis 7.2](https://raw.githubusercontent.com/redis/redis/7.2/00-RELEASENOTES) - using Redis Stack 7.2 for modules support
21-
- [Redis 7.4](https://raw.githubusercontent.com/redis/redis/7.4/00-RELEASENOTES) - using Redis Stack 7.4 for modules support
22-
- [Redis 8.0](https://raw.githubusercontent.com/redis/redis/8.0/00-RELEASENOTES) - using Redis CE 8.0 where modules are included
23-
- [Redis 8.2](https://raw.githubusercontent.com/redis/redis/8.2/00-RELEASENOTES) - using Redis CE 8.2 where modules are included
20+
- [Redis 8.0](https://raw.githubusercontent.com/redis/redis/8.0/00-RELEASENOTES) - using Redis CE 8.0
21+
- [Redis 8.2](https://raw.githubusercontent.com/redis/redis/8.2/00-RELEASENOTES) - using Redis CE 8.2
22+
- [Redis 8.4](https://raw.githubusercontent.com/redis/redis/8.4/00-RELEASENOTES) - using Redis CE 8.4
2423

2524
Although the `go.mod` states it requires at minimum `go 1.18`, our CI is configured to run the tests against all three
2625
versions of Redis and latest two versions of Go ([1.23](https://go.dev/doc/devel/release#go1.23.0),
2726
[1.24](https://go.dev/doc/devel/release#go1.24.0)). We observe that some modules related test may not pass with
2827
Redis Stack 7.2 and some commands are changed with Redis CE 8.0.
28+
Although it is not officially supported, `go-redis/v9` should be able to work with any Redis 7.0+.
2929
Please do refer to the documentation and the tests if you experience any issues. We do plan to update the go version
3030
in the `go.mod` to `go 1.24` in one of the next releases.
3131

@@ -43,10 +43,6 @@ in the `go.mod` to `go 1.24` in one of the next releases.
4343

4444
[Work at Redis](https://redis.com/company/careers/jobs/)
4545

46-
## Documentation
47-
48-
- [English](https://redis.uptrace.dev)
49-
- [简体中文](https://redis.uptrace.dev/zh/)
5046

5147
## Resources
5248

@@ -55,16 +51,18 @@ in the `go.mod` to `go 1.24` in one of the next releases.
5551
- [Reference](https://pkg.go.dev/github.com/redis/go-redis/v9)
5652
- [Examples](https://pkg.go.dev/github.com/redis/go-redis/v9#pkg-examples)
5753

54+
## old documentation
55+
56+
- [English](https://redis.uptrace.dev)
57+
- [简体中文](https://redis.uptrace.dev/zh/)
58+
5859
## Ecosystem
5960

60-
- [Redis Mock](https://github.com/go-redis/redismock)
61+
- [Entra ID (Azure AD)](https://github.com/redis/go-redis-entraid)
6162
- [Distributed Locks](https://github.com/bsm/redislock)
6263
- [Redis Cache](https://github.com/go-redis/cache)
6364
- [Rate limiting](https://github.com/go-redis/redis_rate)
6465

65-
This client also works with [Kvrocks](https://github.com/apache/incubator-kvrocks), a distributed
66-
key value NoSQL database that uses RocksDB as storage engine and is compatible with Redis protocol.
67-
6866
## Features
6967

7068
- Redis commands except QUIT and SYNC.
@@ -75,7 +73,6 @@ key value NoSQL database that uses RocksDB as storage engine and is compatible w
7573
- [Scripting](https://redis.uptrace.dev/guide/lua-scripting.html).
7674
- [Redis Sentinel](https://redis.uptrace.dev/guide/go-redis-sentinel.html).
7775
- [Redis Cluster](https://redis.uptrace.dev/guide/go-redis-cluster.html).
78-
- [Redis Ring](https://redis.uptrace.dev/guide/ring.html).
7976
- [Redis Performance Monitoring](https://redis.uptrace.dev/guide/redis-performance-monitoring.html).
8077
- [Redis Probabilistic [RedisStack]](https://redis.io/docs/data-types/probabilistic/)
8178
- [Customizable read and write buffers size.](#custom-buffer-sizes)
@@ -429,6 +426,144 @@ vals, err := rdb.Eval(ctx, "return {KEYS[1],ARGV[1]}", []string{"key"}, "hello")
429426
res, err := rdb.Do(ctx, "set", "key", "value").Result()
430427
```
431428
429+
## Typed Errors
430+
431+
go-redis provides typed error checking functions for common Redis errors:
432+
433+
```go
434+
// Cluster and replication errors
435+
redis.IsLoadingError(err) // Redis is loading the dataset
436+
redis.IsReadOnlyError(err) // Write to read-only replica
437+
redis.IsClusterDownError(err) // Cluster is down
438+
redis.IsTryAgainError(err) // Command should be retried
439+
redis.IsMasterDownError(err) // Master is down
440+
redis.IsMovedError(err) // Returns (address, true) if key moved
441+
redis.IsAskError(err) // Returns (address, true) if key being migrated
442+
443+
// Connection and resource errors
444+
redis.IsMaxClientsError(err) // Maximum clients reached
445+
redis.IsAuthError(err) // Authentication failed (NOAUTH, WRONGPASS, unauthenticated)
446+
redis.IsPermissionError(err) // Permission denied (NOPERM)
447+
redis.IsOOMError(err) // Out of memory (OOM)
448+
449+
// Transaction errors
450+
redis.IsExecAbortError(err) // Transaction aborted (EXECABORT)
451+
```
452+
453+
### Error Wrapping in Hooks
454+
455+
When wrapping errors in hooks, use custom error types with `Unwrap()` method (preferred) or `fmt.Errorf` with `%w`. Always call `cmd.SetErr()` to preserve error type information:
456+
457+
```go
458+
// Custom error type (preferred)
459+
type AppError struct {
460+
Code string
461+
RequestID string
462+
Err error
463+
}
464+
465+
func (e *AppError) Error() string {
466+
return fmt.Sprintf("[%s] request_id=%s: %v", e.Code, e.RequestID, e.Err)
467+
}
468+
469+
func (e *AppError) Unwrap() error {
470+
return e.Err
471+
}
472+
473+
// Hook implementation
474+
func (h MyHook) ProcessHook(next redis.ProcessHook) redis.ProcessHook {
475+
return func(ctx context.Context, cmd redis.Cmder) error {
476+
err := next(ctx, cmd)
477+
if err != nil {
478+
// Wrap with custom error type
479+
wrappedErr := &AppError{
480+
Code: "REDIS_ERROR",
481+
RequestID: getRequestID(ctx),
482+
Err: err,
483+
}
484+
cmd.SetErr(wrappedErr)
485+
return wrappedErr // Return wrapped error to preserve it
486+
}
487+
return nil
488+
}
489+
}
490+
491+
// Typed error detection works through wrappers
492+
if redis.IsLoadingError(err) {
493+
// Retry logic
494+
}
495+
496+
// Extract custom error if needed
497+
var appErr *AppError
498+
if errors.As(err, &appErr) {
499+
log.Printf("Request: %s", appErr.RequestID)
500+
}
501+
```
502+
503+
Alternatively, use `fmt.Errorf` with `%w`:
504+
```go
505+
wrappedErr := fmt.Errorf("context: %w", err)
506+
cmd.SetErr(wrappedErr)
507+
```
508+
509+
### Pipeline Hook Example
510+
511+
For pipeline operations, use `ProcessPipelineHook`:
512+
513+
```go
514+
type PipelineLoggingHook struct{}
515+
516+
func (h PipelineLoggingHook) DialHook(next redis.DialHook) redis.DialHook {
517+
return next
518+
}
519+
520+
func (h PipelineLoggingHook) ProcessHook(next redis.ProcessHook) redis.ProcessHook {
521+
return next
522+
}
523+
524+
func (h PipelineLoggingHook) ProcessPipelineHook(next redis.ProcessPipelineHook) redis.ProcessPipelineHook {
525+
return func(ctx context.Context, cmds []redis.Cmder) error {
526+
start := time.Now()
527+
528+
// Execute the pipeline
529+
err := next(ctx, cmds)
530+
531+
duration := time.Since(start)
532+
log.Printf("Pipeline executed %d commands in %v", len(cmds), duration)
533+
534+
// Process individual command errors
535+
// Note: Individual command errors are already set on each cmd by the pipeline execution
536+
for _, cmd := range cmds {
537+
if cmdErr := cmd.Err(); cmdErr != nil {
538+
// Check for specific error types using typed error functions
539+
if redis.IsAuthError(cmdErr) {
540+
log.Printf("Auth error in pipeline command %s: %v", cmd.Name(), cmdErr)
541+
} else if redis.IsPermissionError(cmdErr) {
542+
log.Printf("Permission error in pipeline command %s: %v", cmd.Name(), cmdErr)
543+
}
544+
545+
// Optionally wrap individual command errors to add context
546+
// The wrapped error preserves type information through errors.As()
547+
wrappedErr := fmt.Errorf("pipeline cmd %s failed: %w", cmd.Name(), cmdErr)
548+
cmd.SetErr(wrappedErr)
549+
}
550+
}
551+
552+
// Return the pipeline-level error (connection errors, etc.)
553+
// You can wrap it if needed, or return it as-is
554+
return err
555+
}
556+
}
557+
558+
// Register the hook
559+
rdb.AddHook(PipelineLoggingHook{})
560+
561+
// Use pipeline - errors are still properly typed
562+
pipe := rdb.Pipeline()
563+
pipe.Set(ctx, "key1", "value1", 0)
564+
pipe.Get(ctx, "key2")
565+
_, err := pipe.Exec(ctx)
566+
```
432567
433568
## Run the test
434569

0 commit comments

Comments
 (0)