diff --git a/hitless/config.go b/hitless/config.go index 134bb6a6..8645625f 100644 --- a/hitless/config.go +++ b/hitless/config.go @@ -262,6 +262,10 @@ func (c *Config) ApplyDefaultsWithPoolConfig(poolSize int, maxActiveConns int) * var queueCap int if maxActiveConns > 0 { queueCap = maxActiveConns + 1 + // Ensure queue cap is at least 2 for very small maxActiveConns + if queueCap < 2 { + queueCap = 2 + } } else { queueCap = poolSize * 5 } diff --git a/hitless/hitless_manager.go b/hitless/hitless_manager.go index d664534b..6f51b460 100644 --- a/hitless/hitless_manager.go +++ b/hitless/hitless_manager.go @@ -186,6 +186,8 @@ func (hm *HitlessManager) UntrackOperationWithConnID(seqID int64, connID uint64) } // GetActiveMovingOperations returns active operations with composite keys. +// WARNING: This method creates a new map and copies all operations on every call. +// Use sparingly, especially in hot paths or high-frequency logging. func (hm *HitlessManager) GetActiveMovingOperations() map[MovingOperationKey]*MovingOperation { result := make(map[MovingOperationKey]*MovingOperation) diff --git a/hitless/push_notification_handler.go b/hitless/push_notification_handler.go index 9e583ba4..9b3bdf07 100644 --- a/hitless/push_notification_handler.go +++ b/hitless/push_notification_handler.go @@ -130,8 +130,8 @@ func (snh *NotificationHandler) handleMoving(ctx context.Context, handlerCtx pus return } if err := snh.markConnForHandoff(poolConn, newEndpoint, seqID, deadline); err != nil { - // Log error but don't fail the goroutine - internal.Logger.Printf(ctx, "hitless: failed to mark connection for handoff: %v", err) + // Log error but don't fail the goroutine - use background context since original may be cancelled + internal.Logger.Printf(context.Background(), "hitless: failed to mark connection for handoff: %v", err) } }) return nil diff --git a/logging/logging.go b/logging/logging.go index 6218d301..f7e256af 100644 --- a/logging/logging.go +++ b/logging/logging.go @@ -1,3 +1,5 @@ +// Package logging provides logging level constants and utilities for the go-redis library. +// This package centralizes logging configuration to ensure consistency across all components. package logging // LogLevel represents the logging level diff --git a/logging/logging_test.go b/logging/logging_test.go new file mode 100644 index 00000000..9f26d222 --- /dev/null +++ b/logging/logging_test.go @@ -0,0 +1,59 @@ +package logging + +import "testing" + +func TestLogLevel_String(t *testing.T) { + tests := []struct { + level LogLevel + expected string + }{ + {LogLevelError, "ERROR"}, + {LogLevelWarn, "WARN"}, + {LogLevelInfo, "INFO"}, + {LogLevelDebug, "DEBUG"}, + {LogLevel(99), "UNKNOWN"}, + } + + for _, test := range tests { + if got := test.level.String(); got != test.expected { + t.Errorf("LogLevel(%d).String() = %q, want %q", test.level, got, test.expected) + } + } +} + +func TestLogLevel_IsValid(t *testing.T) { + tests := []struct { + level LogLevel + expected bool + }{ + {LogLevelError, true}, + {LogLevelWarn, true}, + {LogLevelInfo, true}, + {LogLevelDebug, true}, + {LogLevel(-1), false}, + {LogLevel(4), false}, + {LogLevel(99), false}, + } + + for _, test := range tests { + if got := test.level.IsValid(); got != test.expected { + t.Errorf("LogLevel(%d).IsValid() = %v, want %v", test.level, got, test.expected) + } + } +} + +func TestLogLevelConstants(t *testing.T) { + // Test that constants have expected values + if LogLevelError != 0 { + t.Errorf("LogLevelError = %d, want 0", LogLevelError) + } + if LogLevelWarn != 1 { + t.Errorf("LogLevelWarn = %d, want 1", LogLevelWarn) + } + if LogLevelInfo != 2 { + t.Errorf("LogLevelInfo = %d, want 2", LogLevelInfo) + } + if LogLevelDebug != 3 { + t.Errorf("LogLevelDebug = %d, want 3", LogLevelDebug) + } +}