Various performance and correctness improvements.
This commit is contained in:
+23
-1
@@ -9,12 +9,24 @@ import (
|
||||
type RetryManager struct {
|
||||
config *RetryConfig
|
||||
retryCount int
|
||||
saturation int
|
||||
}
|
||||
|
||||
func NewRetryManager(config *RetryConfig) *RetryManager {
|
||||
// saturationCount: retry count at which base delay meets or exceeds MaxDelay.
|
||||
// Conservative by one to preserve jitter variance near the boundary.
|
||||
saturation := 0
|
||||
if config != nil &&
|
||||
config.InitialDelay > 0 &&
|
||||
config.InitialDelay <= config.MaxDelay {
|
||||
ratio := float64(config.MaxDelay) / float64(config.InitialDelay)
|
||||
saturation = int(math.Ceil(math.Log2(ratio))) + 2
|
||||
}
|
||||
|
||||
return &RetryManager{
|
||||
config: config,
|
||||
retryCount: 0,
|
||||
saturation: saturation,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,8 +52,18 @@ func (r *RetryManager) CalculateDelay() time.Duration {
|
||||
return 0
|
||||
}
|
||||
|
||||
// if saturation is reached, calculated backoff will always be higher than
|
||||
// the maximum delay
|
||||
if r.config != nil && r.retryCount >= r.saturation {
|
||||
return r.config.MaxDelay
|
||||
}
|
||||
|
||||
// Exponential backoff: InitialDelay * 2^(attempts-1)
|
||||
backoffMultiplier := math.Pow(2, float64(r.retryCount-1))
|
||||
shift := r.retryCount - 1
|
||||
if shift > 62 {
|
||||
shift = 62
|
||||
} // prevent overflow
|
||||
backoffMultiplier := float64(int64(1) << shift)
|
||||
baseDelay := float64(r.config.InitialDelay) * backoffMultiplier
|
||||
|
||||
// Apply jitter: delay * (1 + jitterFactor * (random - 0.5))
|
||||
|
||||
Reference in New Issue
Block a user