throttle/throttle.go (46 lines of code) (raw):
package throttle
import "time"
//Throttle implements generic Throttler
type Throttle struct {
CheckInterval int64
NumSamples int64
Target int64
current int64
samples []int64
sumSamples int64
samplesHand int64
ticker *time.Ticker
}
//New creates new Throttler
func New(target int64, checkInterval int64, numSamples int64) *Throttle {
return &Throttle{checkInterval, numSamples, target, 0, make([]int64, numSamples), 0, 0, time.NewTicker(time.Microsecond * time.Duration(checkInterval))}
}
func (t *Throttle) tick() int64 {
t.sumSamples -= t.samples[t.samplesHand]
t.sumSamples += t.current
t.samples[t.samplesHand] = t.current
t.current = 0
t.samplesHand++
if t.samplesHand >= t.NumSamples {
t.samplesHand = 0
}
avg := t.sumSamples / t.NumSamples
if avg <= t.Target {
return 0
}
return t.CheckInterval - t.CheckInterval*t.Target/(avg)
}
//Advice return a sleep advice to satisfy throttling requirements
func (t *Throttle) Advice(add int64) int64 {
var s int64
t.current += add
if t.Target == 0 {
return 0
}
select {
case <-t.ticker.C:
s = t.tick()
default:
}
return s
}
//Close releases resources
func (t *Throttle) Close() {
t.ticker.Stop()
}