mirror of
https://github.com/redis/go-redis.git
synced 2025-07-29 17:41:15 +03:00
feat: fix connection health check interference with push notifications
- Add PushNotificationProcessor field to pool.Conn for connection-level processing - Modify connection pool Put() and isHealthyConn() to handle push notifications - Process pending push notifications before discarding connections - Pass push notification processor to connections during creation - Update connection pool options to include push notification processor - Add comprehensive test for connection health check integration This prevents connections with buffered push notification data from being incorrectly discarded by the connection health check, ensuring push notifications are properly processed and connections are reused.
This commit is contained in:
@ -25,6 +25,12 @@ type Conn struct {
|
||||
createdAt time.Time
|
||||
|
||||
onClose func() error
|
||||
|
||||
// Push notification processor for handling push notifications on this connection
|
||||
PushNotificationProcessor interface {
|
||||
IsEnabled() bool
|
||||
ProcessPendingNotifications(ctx context.Context, rd *proto.Reader) error
|
||||
}
|
||||
}
|
||||
|
||||
func NewConn(netConn net.Conn) *Conn {
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/redis/go-redis/v9/internal"
|
||||
"github.com/redis/go-redis/v9/internal/proto"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -71,6 +72,12 @@ type Options struct {
|
||||
MaxActiveConns int
|
||||
ConnMaxIdleTime time.Duration
|
||||
ConnMaxLifetime time.Duration
|
||||
|
||||
// Push notification processor for connections
|
||||
PushNotificationProcessor interface {
|
||||
IsEnabled() bool
|
||||
ProcessPendingNotifications(ctx context.Context, rd *proto.Reader) error
|
||||
}
|
||||
}
|
||||
|
||||
type lastDialErrorWrap struct {
|
||||
@ -228,6 +235,12 @@ func (p *ConnPool) dialConn(ctx context.Context, pooled bool) (*Conn, error) {
|
||||
|
||||
cn := NewConn(netConn)
|
||||
cn.pooled = pooled
|
||||
|
||||
// Set push notification processor if available
|
||||
if p.cfg.PushNotificationProcessor != nil {
|
||||
cn.PushNotificationProcessor = p.cfg.PushNotificationProcessor
|
||||
}
|
||||
|
||||
return cn, nil
|
||||
}
|
||||
|
||||
@ -377,9 +390,24 @@ func (p *ConnPool) popIdle() (*Conn, error) {
|
||||
|
||||
func (p *ConnPool) Put(ctx context.Context, cn *Conn) {
|
||||
if cn.rd.Buffered() > 0 {
|
||||
internal.Logger.Printf(ctx, "Conn has unread data")
|
||||
p.Remove(ctx, cn, BadConnError{})
|
||||
return
|
||||
// Check if this might be push notification data
|
||||
if cn.PushNotificationProcessor != nil && cn.PushNotificationProcessor.IsEnabled() {
|
||||
// Try to process pending push notifications before discarding connection
|
||||
err := cn.PushNotificationProcessor.ProcessPendingNotifications(ctx, cn.rd)
|
||||
if err != nil {
|
||||
internal.Logger.Printf(ctx, "push: error processing pending notifications: %v", err)
|
||||
}
|
||||
// Check again if there's still unread data after processing push notifications
|
||||
if cn.rd.Buffered() > 0 {
|
||||
internal.Logger.Printf(ctx, "Conn has unread data after processing push notifications")
|
||||
p.Remove(ctx, cn, BadConnError{})
|
||||
return
|
||||
}
|
||||
} else {
|
||||
internal.Logger.Printf(ctx, "Conn has unread data")
|
||||
p.Remove(ctx, cn, BadConnError{})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !cn.pooled {
|
||||
@ -523,8 +551,24 @@ func (p *ConnPool) isHealthyConn(cn *Conn) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
if connCheck(cn.netConn) != nil {
|
||||
return false
|
||||
// Check connection health, but be aware of push notifications
|
||||
if err := connCheck(cn.netConn); err != nil {
|
||||
// If there's unexpected data and we have push notification support,
|
||||
// it might be push notifications
|
||||
if err == errUnexpectedRead && cn.PushNotificationProcessor != nil && cn.PushNotificationProcessor.IsEnabled() {
|
||||
// Try to process any pending push notifications
|
||||
ctx := context.Background()
|
||||
if procErr := cn.PushNotificationProcessor.ProcessPendingNotifications(ctx, cn.rd); procErr != nil {
|
||||
internal.Logger.Printf(ctx, "push: error processing pending notifications during health check: %v", procErr)
|
||||
return false
|
||||
}
|
||||
// Check again after processing push notifications
|
||||
if connCheck(cn.netConn) != nil {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
cn.SetUsedAt(now)
|
||||
|
Reference in New Issue
Block a user