@@ -103,30 +103,25 @@ type Config struct {
103103
104104 // MaxWorkers is the maximum number of worker goroutines for processing handoff requests.
105105 // Workers are created on-demand and automatically cleaned up when idle.
106- // If zero, defaults to min(10, PoolSize/3 ) to handle bursts effectively.
107- // If explicitly set, enforces minimum of 10 workers.
106+ // If zero, defaults to min(10, PoolSize/2 ) to handle bursts effectively.
107+ // If explicitly set, enforces minimum of PoolSize/2
108108 //
109- // Default: min(10, PoolSize/3), Minimum when set: 10
109+ // Default: min(PoolSize/2, max( 10, PoolSize/3)) , Minimum when set: PoolSize/2
110110 MaxWorkers int
111111
112112 // HandoffQueueSize is the size of the buffered channel used to queue handoff requests.
113113 // If the queue is full, new handoff requests will be rejected.
114114 // Scales with both worker count and pool size for better burst handling.
115115 //
116- // Default: max(8x workers, max(50, PoolSize/2)) , capped by 2x pool size
117- // When set: min 50 , capped by 2x pool size
116+ // Default: max(20×MaxWorkers, PoolSize) , capped by MaxActiveConns+1 (if set) or 5×PoolSize
117+ // When set: minimum 200 , capped by MaxActiveConns+1 (if set) or 5×PoolSize
118118 HandoffQueueSize int
119119
120120 // PostHandoffRelaxedDuration is how long to keep relaxed timeouts on the new connection
121121 // after a handoff completes. This provides additional resilience during cluster transitions.
122122 // Default: 2 * RelaxedTimeout
123123 PostHandoffRelaxedDuration time.Duration
124124
125- // ScaleDownDelay is the delay before checking if workers should be scaled down.
126- // This prevents expensive checks on every handoff completion and avoids rapid scaling cycles.
127- // Default: 2 seconds
128- ScaleDownDelay time.Duration
129-
130125 // LogLevel controls the verbosity of hitless upgrade logging.
131126 // LogLevelError (0) = errors only, LogLevelWarn (1) = warnings, LogLevelInfo (2) = info, LogLevelDebug (3) = debug
132127 // Default: LogLevelWarn (warnings)
@@ -152,7 +147,6 @@ func DefaultConfig() *Config {
152147 MaxWorkers : 0 , // Auto-calculated based on pool size
153148 HandoffQueueSize : 0 , // Auto-calculated based on max workers
154149 PostHandoffRelaxedDuration : 0 , // Auto-calculated based on relaxed timeout
155- ScaleDownDelay : 2 * time .Second ,
156150 LogLevel : LogLevelWarn ,
157151
158152 // Connection Handoff Configuration
@@ -212,6 +206,13 @@ func (c *Config) ApplyDefaults() *Config {
212206// using the provided pool size to calculate worker defaults.
213207// This ensures that partially configured structs get sensible defaults for missing fields.
214208func (c * Config ) ApplyDefaultsWithPoolSize (poolSize int ) * Config {
209+ return c .ApplyDefaultsWithPoolConfig (poolSize , 0 )
210+ }
211+
212+ // ApplyDefaultsWithPoolConfig applies default values to any zero-value fields in the configuration,
213+ // using the provided pool size and max active connections to calculate worker and queue defaults.
214+ // This ensures that partially configured structs get sensible defaults for missing fields.
215+ func (c * Config ) ApplyDefaultsWithPoolConfig (poolSize int , maxActiveConns int ) * Config {
215216 if c == nil {
216217 return DefaultConfig ().ApplyDefaultsWithPoolSize (poolSize )
217218 }
@@ -251,19 +252,25 @@ func (c *Config) ApplyDefaultsWithPoolSize(poolSize int) *Config {
251252 // Apply worker defaults based on pool size
252253 result .applyWorkerDefaults (poolSize )
253254
254- // Apply queue size defaults with hybrid scaling approach
255+ // Apply queue size defaults with new scaling approach
255256 if c .HandoffQueueSize <= 0 {
256- // Default: max(8x workers, max(50, PoolSize/2)) , capped by 2x pool size
257- workerBasedSize := result .MaxWorkers * 8
258- poolBasedSize := util . Max ( 50 , poolSize / 2 )
257+ // Default: max(20x workers, PoolSize) , capped by maxActiveConns or 5x pool size
258+ workerBasedSize := result .MaxWorkers * 20
259+ poolBasedSize := poolSize
259260 result .HandoffQueueSize = util .Max (workerBasedSize , poolBasedSize )
260261 } else {
261- // When explicitly set: enforce minimum of 50
262- result .HandoffQueueSize = util .Max (50 , c .HandoffQueueSize )
262+ // When explicitly set: enforce minimum of 200
263+ result .HandoffQueueSize = util .Max (200 , c .HandoffQueueSize )
263264 }
264265
265- // Always cap queue size by 2x pool size - balances burst capacity with memory efficiency
266- result .HandoffQueueSize = util .Min (result .HandoffQueueSize , poolSize * 2 )
266+ // Cap queue size: use maxActiveConns+1 if set, otherwise 5x pool size
267+ var queueCap int
268+ if maxActiveConns > 0 {
269+ queueCap = maxActiveConns + 1
270+ } else {
271+ queueCap = poolSize * 5
272+ }
273+ result .HandoffQueueSize = util .Min (result .HandoffQueueSize , queueCap )
267274
268275 // Ensure minimum queue size of 2 (fallback for very small pools)
269276 if result .HandoffQueueSize < 2 {
@@ -276,12 +283,6 @@ func (c *Config) ApplyDefaultsWithPoolSize(poolSize int) *Config {
276283 result .PostHandoffRelaxedDuration = c .PostHandoffRelaxedDuration
277284 }
278285
279- if c .ScaleDownDelay <= 0 {
280- result .ScaleDownDelay = defaults .ScaleDownDelay
281- } else {
282- result .ScaleDownDelay = c .ScaleDownDelay
283- }
284-
285286 // LogLevel: 0 is a valid value (errors only), so we need to check if it was explicitly set
286287 // We'll use the provided value as-is, since 0 is valid
287288 result .LogLevel = c .LogLevel
@@ -314,7 +315,6 @@ func (c *Config) Clone() *Config {
314315 MaxWorkers : c .MaxWorkers ,
315316 HandoffQueueSize : c .HandoffQueueSize ,
316317 PostHandoffRelaxedDuration : c .PostHandoffRelaxedDuration ,
317- ScaleDownDelay : c .ScaleDownDelay ,
318318 LogLevel : c .LogLevel ,
319319
320320 // Configuration fields
@@ -330,11 +330,11 @@ func (c *Config) applyWorkerDefaults(poolSize int) {
330330 }
331331
332332 if c .MaxWorkers == 0 {
333- // When not set: min(10, poolSize/3) - don't exceed 10 workers for small pools
334- c .MaxWorkers = util .Min (10 , poolSize / 3 )
333+ // When not set: min(poolSize/2, max( 10, poolSize/3)) - balanced scaling approach
334+ c .MaxWorkers = util .Min (poolSize / 2 , util . Max ( 10 , poolSize / 3 ) )
335335 } else {
336- // When explicitly set: max(10 , set_value) - ensure at least 10 workers
337- c .MaxWorkers = util .Max (10 , c .MaxWorkers )
336+ // When explicitly set: max(poolSize/2 , set_value) - ensure at least poolSize/2 workers
337+ c .MaxWorkers = util .Max (poolSize / 2 , c .MaxWorkers )
338338 }
339339
340340 // Ensure minimum of 1 worker (fallback for very small pools)
0 commit comments