github.com/msales/pkg/v3@v3.24.0/retry/retry.go (about) 1 package retry 2 3 import ( 4 "errors" 5 "time" 6 ) 7 8 // Policy determines how Run retries the function. 9 type Policy interface { 10 Next() (time.Duration, bool) 11 } 12 13 type exponentialPolicy struct { 14 attempts int 15 sleep time.Duration 16 } 17 18 // ExponentialPolicy retires with an exponential growth in sleep. 19 func ExponentialPolicy(attempts int, sleep time.Duration) Policy { 20 return &exponentialPolicy{ 21 attempts: attempts, 22 sleep: sleep, 23 } 24 } 25 26 func (p *exponentialPolicy) Next() (time.Duration, bool) { 27 p.attempts-- 28 if p.attempts <= 0 { 29 return 0, false 30 } 31 32 defer func() { 33 p.sleep *= 2 34 }() 35 36 return p.sleep, true 37 } 38 39 // Run executes the function while the Policy allows 40 // until it returns nil or Stop. 41 func Run(p Policy, fn func() error) error { 42 if p == nil { 43 return errors.New("policy must not be nil") 44 } 45 46 if err := fn(); err != nil { 47 if s, ok := err.(stop); ok { 48 return s.error 49 } 50 51 if sleep, ok := p.Next(); ok { 52 time.Sleep(sleep) 53 Run(p, fn) 54 } 55 56 return err 57 } 58 59 return nil 60 } 61 62 type stop struct { 63 error 64 } 65 66 // Stop wraps an error and stops retrying. 67 func Stop(err error) error { 68 return stop{err} 69 }