1package cbreaker 2 3import ( 4 "fmt" 5 "time" 6 7 "github.com/mailgun/timetools" 8 log "github.com/sirupsen/logrus" 9) 10 11// ratioController allows passing portions traffic back to the endpoints, 12// increasing the amount of passed requests using linear function: 13// 14// allowedRequestsRatio = 0.5 * (Now() - Start())/Duration 15// 16type ratioController struct { 17 duration time.Duration 18 start time.Time 19 tm timetools.TimeProvider 20 allowed int 21 denied int 22 23 log *log.Logger 24} 25 26func newRatioController(tm timetools.TimeProvider, rampUp time.Duration, log *log.Logger) *ratioController { 27 return &ratioController{ 28 duration: rampUp, 29 tm: tm, 30 start: tm.UtcNow(), 31 32 log: log, 33 } 34} 35 36func (r *ratioController) String() string { 37 return fmt.Sprintf("RatioController(target=%f, current=%f, allowed=%d, denied=%d)", r.targetRatio(), r.computeRatio(r.allowed, r.denied), r.allowed, r.denied) 38} 39 40func (r *ratioController) allowRequest() bool { 41 r.log.Debugf("%v", r) 42 t := r.targetRatio() 43 // This condition answers the question - would we satisfy the target ratio if we allow this request? 44 e := r.computeRatio(r.allowed+1, r.denied) 45 if e < t { 46 r.allowed++ 47 r.log.Debugf("%v allowed", r) 48 return true 49 } 50 r.denied++ 51 r.log.Debugf("%v denied", r) 52 return false 53} 54 55func (r *ratioController) computeRatio(allowed, denied int) float64 { 56 if denied+allowed == 0 { 57 return 0 58 } 59 return float64(allowed) / float64(denied+allowed) 60} 61 62func (r *ratioController) targetRatio() float64 { 63 // Here's why it's 0.5: 64 // We are watching the following ratio 65 // ratio = a / (a + d) 66 // We can notice, that once we get to 0.5 67 // 0.5 = a / (a + d) 68 // we can evaluate that a = d 69 // that means equilibrium, where we would allow all the requests 70 // after this point to achieve ratio of 1 (that can never be reached unless d is 0) 71 // so we stop from there 72 multiplier := 0.5 / float64(r.duration) 73 return multiplier * float64(r.tm.UtcNow().Sub(r.start)) 74} 75