1package backoff 2 3import ( 4 "math" 5 "time" 6) 7 8/* 9ExponentialBackoff implements the Backoff interface. It represents an 10instance that keeps track of retries, delays, and intervals for the 11fibonacci backoff algorithm. This struct is instantiated by 12the Exponential() function. 13*/ 14type ExponentialBackoff struct { 15 Retries int 16 MaxRetries int 17 Delay time.Duration 18 Interval time.Duration // time.Second, time.Millisecond, etc. 19} 20 21// Exponential creates a new instance of ExponentialBackoff. 22func Exponential() *ExponentialBackoff { 23 return &ExponentialBackoff{ 24 Retries: 0, 25 MaxRetries: 5, 26 Delay: time.Duration(0), 27 Interval: time.Duration(1 * time.Second), 28 } 29} 30 31/* 32Next gets the next backoff delay. This method will increment the retries and check 33if the maximum number of retries has been met. If this condition is satisfied, then 34the function will return. Otherwise, the next backoff delay will be computed. 35 36The exponential backoff delay is computed as follows: 37`n = 2^c - 1` where `n` is the backoff delay and `c` is the number of retries. 38 39Example, given a 1 second interval: 40 41 Retry # Backoff delay (in seconds) 42 0 0 43 1 1 44 2 3 45 3 7 46 4 15 47 5 31 48*/ 49func (e *ExponentialBackoff) Next() bool { 50 if e.Retries >= e.MaxRetries { 51 return false 52 } 53 54 e.Retries++ 55 56 e.Delay = time.Duration(math.Pow(2, float64(e.Retries))-1) * e.Interval 57 58 return true 59} 60 61/* 62Retry will retry a function until the maximum number of retries is met. This method expects 63the function `f` to return an error. If the failure condition is met, this method 64will surface the error outputted from `f`, otherwise nil will be returned as normal. 65*/ 66func (e *ExponentialBackoff) Retry(f func() error) error { 67 err := f() 68 69 if err == nil { 70 return nil 71 } 72 73 for e.Next() { 74 if err = f(); err == nil { 75 return nil 76 } 77 78 time.Sleep(e.Delay) 79 } 80 81 return err 82} 83 84// Reset will reset the retry count and the backoff delay back to its initial state. 85func (e *ExponentialBackoff) Reset() { 86 e.Retries = 0 87 e.Delay = time.Duration(0 * time.Second) 88} 89