1s, 2s, 3s, 4s, 5s, ...
and stops growing once request is successful// for each failure we add interval to current delay
func sleepTime(currentDelay, interval, maxInterval int64) int64 {
currentDelay += interval
if currentDelay > maxInterval {
currentDelay = maxInterval
}
return currentDelay
}
1s, 2s, 4s, 8s, 16s, ...
// for each failure we multiple the current delay by a multiplication factor
func sleepTime(currentDelay, initialDelay, maxInterval int64, multiplier float64) int64 {
if currentDelay == 0 {
return initialDelay
}
currentDelay = int64(float64(currentDelay) * multiplier)
if currentDelay > maxInterval {
return maxInterval
}
return currentDelay
}
responsive exponential back off
to handle this rate limitingRandomizationFactor=0.2
, current delay is 1s
and up multiplier 2
, on next failure it can become (1 x 2) +/- 0.2 * (1 x 2) = 1.6 to 2.4
Following configurations are used for the sleeper.
type AutoSleeper struct {
InitialInterval time.Duration // Used for sleeping first time
MaxInterval time.Duration // Max interval for sleeping
MaxRandomization time.Duration // Max randomization interval
UpMultiplier float64 // Multiplied for increasing the sleep time
DownMultiplier float64 // Multiplied for decreasing the sleep time
RandomizationFactor float64 // Randomize the new sleep value
DownMultiplierThreshold int // Threshold for triggering sleep time reduction
}
https://github.com/sakthipriyan/go-utils/blob/main/sleeper.go
package main
import (
"math/rand"
"time"
)
const (
DefaultMaxInterval = 15 * time.Minute
DefaultInitialInterval = 500 * time.Millisecond
DefaultRandomizationFactor = 0.3
DefaultMaxRandomization = 2 * time.Minute
DefaultUpMultiplier = 1.5
DefaultDownMultiplier = 0.9
DefaultDownMultiplierThreshold = 10
)
func NewAutoSleeper() *AutoSleeper {
return &AutoSleeper{
MaxInterval: DefaultMaxInterval,
InitialInterval: DefaultInitialInterval,
RandomizationFactor: DefaultRandomizationFactor,
MaxRandomization: DefaultMaxRandomization,
UpMultiplier: DefaultUpMultiplier,
DownMultiplier: DefaultDownMultiplier,
DownMultiplierThreshold: DefaultDownMultiplierThreshold,
}
}
type AutoSleeperMetrics struct {
TotalInvocation int
TotalWentUp int
TotalWentDown int
TotalSlept int
TotalSleepTime time.Duration
}
type AutoSleeper struct {
InitialInterval time.Duration
MaxInterval time.Duration
MaxRandomization time.Duration
UpMultiplier float64
DownMultiplier float64
RandomizationFactor float64
DownMultiplierThreshold int
metrics AutoSleeperMetrics
currentInterval time.Duration
currentSuccess int
}
func (s *AutoSleeper) GetMetrics() AutoSleeperMetrics {
return s.metrics
}
func (s *AutoSleeper) SleepOnFailure() {
s.metrics.TotalInvocation += 1
s.goUp()
s.sleep()
}
func (s *AutoSleeper) SleepOnSuccess() {
s.metrics.TotalInvocation += 1
if s.currentInterval == 0 {
return
}
s.currentSuccess += 1
if s.currentSuccess == s.DownMultiplierThreshold {
s.goDown()
s.currentSuccess = 0
}
s.sleep()
}
func (s *AutoSleeper) sleep() {
s.metrics.TotalSleepTime += s.currentInterval
s.metrics.TotalSlept += 1
time.Sleep(s.currentInterval)
}
func (s *AutoSleeper) goDown() {
s.metrics.TotalWentDown += 1
interval := float64(s.currentInterval) * s.DownMultiplier
random := getNextRandomInterval(interval, s.RandomizationFactor, float64(s.MaxRandomization))
if random < float64(s.InitialInterval) {
s.currentInterval = 0
return
}
s.currentInterval = time.Duration(random)
}
func (s *AutoSleeper) goUp() {
s.metrics.TotalWentUp += 1
if s.currentInterval == 0 {
s.currentInterval = s.InitialInterval
return
}
interval := float64(s.currentInterval) * s.UpMultiplier
random := getNextRandomInterval(interval, s.RandomizationFactor, float64(s.MaxRandomization))
if random > float64(s.MaxInterval) {
s.currentInterval = s.MaxInterval
return
}
s.currentInterval = time.Duration(random)
}
func getNextRandomInterval(currentInterval, randomizationFactor, maxRandomization float64) float64 {
if randomizationFactor == 0 {
return currentInterval
}
delta := randomizationFactor * currentInterval
if delta > maxRandomization {
delta = maxRandomization
}
randomization := 2 * delta * rand.Float64()
minInterval := currentInterval - delta
return minInterval + randomization
}
s := NewAutoSleeper()
s.SleepOnFailure() // Uses up multiplier
s.SleepOnSuccess() // Uses down multiplier on N threshold
For the following configuration,
InitialInterval = 1 millisecond
MaxInterval = 15 minutes
MaxRandomization = 2 minutes
UpMultiplier = 1.5
DownMultiplier = 0.6
RandomizationFactor = 0.0
DownMultiplierThreshold = 5
291.9 ms
60 ms
were succeedingDownMultiplierThreshold
controls how frequently we want to reduce the delayDownMultiplier
controls how fast we want to reduce the delayRandomizationFactor
and MaxRandomization
controls the noise introduced while scaling up/down
Building machine learning models
spark
scala
sbt
bigdata
code
machine learning
|
|
Feature engineering for machine learning models
spark
scala
sbt
bigdata
code
machine learning
|