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
59 changes: 59 additions & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,64 @@
# Release Notes

# 9.16.0 (2025-10-23)

## 🚀 Highlights

### Maintenance Notifications Support

This release introduces comprehensive support for Redis maintenance notifications, enabling applications to handle server maintenance events gracefully. The new `maintnotifications` package provides:

- **RESP3 Push Notifications**: Full support for Redis RESP3 protocol push notifications
- **Connection Handoff**: Automatic connection migration during server maintenance with configurable retry policies and circuit breakers
- **Graceful Degradation**: Configurable timeout relaxation during maintenance windows to prevent false failures
- **Event-Driven Architecture**: Background workers with on-demand scaling for efficient handoff processing
- **Production-Ready**: Comprehensive E2E testing framework and monitoring capabilities

For detailed usage examples and configuration options, see the [maintenance notifications documentation](maintnotifications/README.md).

## ✨ New Features

- **Trace Filtering**: Add support for filtering traces for specific commands, including pipeline operations and dial operations ([#3519](https://github.com/redis/go-redis/pull/3519), [#3550](https://github.com/redis/go-redis/pull/3550))
- New `TraceCmdFilter` option to selectively trace commands
- Reduces overhead by excluding high-frequency or low-value commands from traces

## 🐛 Bug Fixes

- **Pipeline Error Handling**: Fix issue where pipeline repeatedly sets the same error ([#3525](https://github.com/redis/go-redis/pull/3525))
- **Connection Pool**: Ensure re-authentication does not interfere with connection handoff operations ([#3547](https://github.com/redis/go-redis/pull/3547))

## 🔧 Improvements

- **Hash Commands**: Update hash command implementations ([#3523](https://github.com/redis/go-redis/pull/3523))
- **OpenTelemetry**: Use `metric.WithAttributeSet` to avoid unnecessary attribute copying in redisotel ([#3552](https://github.com/redis/go-redis/pull/3552))

## 📚 Documentation

- **Cluster Client**: Add explanation for why `MaxRetries` is disabled for `ClusterClient` ([#3551](https://github.com/redis/go-redis/pull/3551))

## 🧪 Testing & Infrastructure

- **E2E Testing**: Upgrade E2E testing framework with improved reliability and coverage ([#3541](https://github.com/redis/go-redis/pull/3541))
- **Release Process**: Improved resiliency of the release process ([#3530](https://github.com/redis/go-redis/pull/3530))

## 📦 Dependencies

- Bump `rojopolis/spellcheck-github-actions` from 0.51.0 to 0.52.0 ([#3520](https://github.com/redis/go-redis/pull/3520))
- Bump `github/codeql-action` from 3 to 4 ([#3544](https://github.com/redis/go-redis/pull/3544))

## 👥 Contributors

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

[@ndyakov](https://github.com/ndyakov), [@htemelski-redis](https://github.com/htemelski-redis), [@Sovietaced](https://github.com/Sovietaced), [@Udhayarajan](https://github.com/Udhayarajan), [@boekkooi-impossiblecloud](https://github.com/boekkooi-impossiblecloud), [@Pika-Gopher](https://github.com/Pika-Gopher), [@cxljs](https://github.com/cxljs), [@huiyifyj](https://github.com/huiyifyj), [@omid-h70](https://github.com/omid-h70)

---

**Full Changelog**: https://github.com/redis/go-redis/compare/v9.14.0...v9.16.0


# 9.15.0 was accidentally released. Please use version 9.16.0 instead.

# 9.15.0-beta.3 (2025-09-26)

## Highlights
Expand Down
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.16.0-beta.1
github.com/redis/go-redis/v9 v9.16.0
go.uber.org/zap v1.24.0
)

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.16.0-beta.1
require github.com/redis/go-redis/v9 v9.16.0

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.16.0-beta.1
github.com/redis/go-redis/v9 v9.16.0
)

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.16.0-beta.1
require github.com/redis/go-redis/v9 v9.16.0

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.16.0-beta.1
github.com/redis/go-redis/v9 v9.16.0-beta.1
github.com/redis/go-redis/extra/redisotel/v9 v9.16.0
github.com/redis/go-redis/v9 v9.16.0
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.16.0-beta.1 // indirect
github.com/redis/go-redis/extra/rediscmd/v9 v9.16.0 // 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.16.0-beta.1
require github.com/redis/go-redis/v9 v9.16.0

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.16.0-beta.1
github.com/redis/go-redis/v9 v9.16.0
)

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.16.0-beta.1
github.com/redis/go-redis/v9 v9.16.0-beta.1
github.com/redis/go-redis/extra/rediscmd/v9 v9.16.0
github.com/redis/go-redis/v9 v9.16.0
go.opencensus.io v0.24.0
)

Expand Down
2 changes: 1 addition & 1 deletion extra/rediscmd/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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.16.0-beta.1
github.com/redis/go-redis/v9 v9.16.0
)

require (
Expand Down
4 changes: 2 additions & 2 deletions extra/redisotel/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.16.0-beta.1
github.com/redis/go-redis/v9 v9.16.0-beta.1
github.com/redis/go-redis/extra/rediscmd/v9 v9.16.0
github.com/redis/go-redis/v9 v9.16.0
go.opentelemetry.io/otel v1.22.0
go.opentelemetry.io/otel/metric v1.22.0
go.opentelemetry.io/otel/sdk v1.22.0
Expand Down
2 changes: 1 addition & 1 deletion extra/redisprometheus/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/prometheus/client_golang v1.14.0
github.com/redis/go-redis/v9 v9.16.0-beta.1
github.com/redis/go-redis/v9 v9.16.0
)

require (
Expand Down
218 changes: 218 additions & 0 deletions maintnotifications/FEATURES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
# Maintenance Notifications - FEATURES

## Overview

The Maintenance Notifications feature enables seamless Redis connection handoffs during cluster maintenance operations without dropping active connections. This feature leverages Redis RESP3 push notifications to provide zero-downtime maintenance for Redis Enterprise and compatible Redis deployments.

## Important

Using Maintenance Notifications may affect the read and write timeouts by relaxing them during maintenance operations.
This is necessary to prevent false failures due to increased latency during handoffs. The relaxed timeouts are automatically applied and removed as needed.

## Key Features

### Seamless Connection Handoffs
- **Zero-Downtime Maintenance**: Automatically handles connection transitions during cluster operations
- **Active Operation Preservation**: Transfers in-flight operations to new connections without interruption
- **Graceful Degradation**: Falls back to standard reconnection if handoff fails

### Push Notification Support
Supports all Redis Enterprise maintenance notification types:
- **MOVING** - Slot moving to a new node
- **MIGRATING** - Slot in migration state
- **MIGRATED** - Migration completed
- **FAILING_OVER** - Node failing over
- **FAILED_OVER** - Failover completed

### Circuit Breaker Pattern
- **Endpoint-Specific Failure Tracking**: Prevents repeated connection attempts to failing endpoints
- **Automatic Recovery Testing**: Half-open state allows gradual recovery validation
- **Configurable Thresholds**: Customize failure thresholds and reset timeouts

### Flexible Configuration
- **Auto-Detection Mode**: Automatically detects server support for maintenance notifications
- **Multiple Endpoint Types**: Support for internal/external IP/FQDN endpoint resolution
- **Auto-Scaling Workers**: Automatically sizes worker pool based on connection pool size
- **Timeout Management**: Separate timeouts for relaxed (during maintenance) and normal operations

### Extensible Hook System
- **Pre/Post Processing Hooks**: Monitor and customize notification handling
- **Built-in Hooks**: Logging and metrics collection hooks included
- **Custom Hook Support**: Implement custom business logic around maintenance events

### Comprehensive Monitoring
- **Metrics Collection**: Track notification counts, processing times, and error rates
- **Circuit Breaker Stats**: Monitor endpoint health and circuit breaker states
- **Operation Tracking**: Track active handoff operations and their lifecycle

## Architecture Highlights

### Event-Driven Handoff System
- **Asynchronous Processing**: Non-blocking handoff operations using worker pool pattern
- **Queue-Based Architecture**: Configurable queue size with auto-scaling support
- **Retry Mechanism**: Configurable retry attempts with exponential backoff

### Connection Pool Integration
- **Pool Hook Interface**: Seamless integration with go-redis connection pool
- **Connection State Management**: Atomic flags for connection usability tracking
- **Graceful Shutdown**: Ensures all in-flight handoffs complete before shutdown

### Thread-Safe Design
- **Lock-Free Operations**: Atomic operations for high-performance state tracking
- **Concurrent-Safe Maps**: sync.Map for tracking active operations
- **Minimal Lock Contention**: Read-write locks only where necessary

## Configuration Options

### Operation Modes
- **`ModeDisabled`**: Maintenance notifications completely disabled
- **`ModeEnabled`**: Forcefully enabled (fails if server doesn't support)
- **`ModeAuto`**: Auto-detect server support (recommended default)

### Endpoint Types
- **`EndpointTypeAuto`**: Auto-detect based on current connection
- **`EndpointTypeInternalIP`**: Use internal IP addresses
- **`EndpointTypeInternalFQDN`**: Use internal fully qualified domain names
- **`EndpointTypeExternalIP`**: Use external IP addresses
- **`EndpointTypeExternalFQDN`**: Use external fully qualified domain names
- **`EndpointTypeNone`**: No endpoint (reconnect with current configuration)

### Timeout Configuration
- **`RelaxedTimeout`**: Extended timeout during maintenance operations (default: 10s)
- **`HandoffTimeout`**: Maximum time for handoff completion (default: 15s)
- **`PostHandoffRelaxedDuration`**: Relaxed period after handoff (default: 2×RelaxedTimeout)

### Worker Pool Configuration
- **`MaxWorkers`**: Maximum concurrent handoff workers (auto-calculated if 0)
- **`HandoffQueueSize`**: Handoff queue capacity (auto-calculated if 0)
- **`MaxHandoffRetries`**: Maximum retry attempts for failed handoffs (default: 3)

### Circuit Breaker Configuration
- **`CircuitBreakerFailureThreshold`**: Failures before opening circuit (default: 5)
- **`CircuitBreakerResetTimeout`**: Time before testing recovery (default: 60s)
- **`CircuitBreakerMaxRequests`**: Max requests in half-open state (default: 3)

## Auto-Scaling Formulas

### Worker Pool Sizing
When `MaxWorkers = 0` (auto-calculate):
```
MaxWorkers = min(PoolSize/2, max(10, PoolSize/3))
```

### Queue Sizing
When `HandoffQueueSize = 0` (auto-calculate):
```
QueueSize = max(20 × MaxWorkers, PoolSize)
Capped by: min(MaxActiveConns + 1, 5 × PoolSize)
```

### Examples
- **Pool Size 100**: 33 workers, 660 queue (capped at 500)
- **Pool Size 100 + MaxActiveConns 150**: 33 workers, 151 queue
- **Pool Size 50**: 16 workers, 320 queue (capped at 250)

## Performance Characteristics

### Throughput
- **Non-Blocking Handoffs**: Client operations continue during handoffs
- **Concurrent Processing**: Multiple handoffs processed in parallel
- **Minimal Overhead**: Lock-free atomic operations for state tracking

### Latency
- **Relaxed Timeouts**: Extended timeouts during maintenance prevent false failures
- **Fast Path**: Connections not undergoing handoff have zero overhead
- **Graceful Degradation**: Failed handoffs fall back to standard reconnection

### Resource Usage
- **Memory Efficient**: Bounded queue sizes prevent memory exhaustion
- **Worker Pool**: Fixed worker count prevents goroutine explosion
- **Connection Reuse**: Handoff reuses existing connection objects

## Testing

### Unit Tests
- Comprehensive unit test coverage for all components
- Mock-based testing for isolation
- Concurrent operation testing

### Integration Tests
- Pool integration tests with real connection handoffs
- Circuit breaker behavior validation
- Hook system integration testing

### E2E Tests
- Real Redis Enterprise cluster testing
- Multiple scenario coverage (timeouts, endpoint types, stress tests)
- Fault injection testing
- TLS configuration testing

## Compatibility

### Requirements
- **Redis Protocol**: RESP3 required for push notifications
- **Redis Version**: Redis Enterprise or compatible Redis with maintenance notifications
- **Go Version**: Go 1.18+ (uses generics and atomic types)

### Client Support
#### Currently Supported
- **Standalone Client** (`redis.NewClient`)

#### Planned Support
- **Cluster Client** (not yet supported)

#### Will Not Support
- **Failover Client** (no planned support)
- **Ring Client** (no planned support)

## Migration Guide

### Enabling Maintenance Notifications

**Before:**
```go
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Protocol: 2, // RESP2
})
```

**After:**
```go
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Protocol: 3, // RESP3 required
MaintNotificationsConfig: &maintnotifications.Config{
Mode: maintnotifications.ModeAuto,
},
})
```

### Adding Monitoring

```go
// Get the manager from the client
manager := client.GetMaintNotificationsManager()
if manager != nil {
// Add logging hook
loggingHook := maintnotifications.NewLoggingHook(2) // Info level
manager.AddNotificationHook(loggingHook)

// Add metrics hook
metricsHook := maintnotifications.NewMetricsHook()
manager.AddNotificationHook(metricsHook)
}
```

## Known Limitations

1. **Standalone Only**: Currently only supported in standalone Redis clients
2. **RESP3 Required**: Push notifications require RESP3 protocol
3. **Server Support**: Requires Redis Enterprise or compatible Redis with maintenance notifications
4. **Single Connection Commands**: Some commands (MULTI/EXEC, WATCH) may need special handling
5. **No Failover/Ring Client Support**: Failover and Ring clients are not supported and there are no plans to add support

## Future Enhancements

- Cluster client support
- Enhanced metrics and observability
Loading
Loading