68 строки
1.4 KiB
Go
68 строки
1.4 KiB
Go
package common
|
|
|
|
import (
|
|
"errors"
|
|
"math"
|
|
"time"
|
|
)
|
|
|
|
// WithAttempts executes a function N times or until no error is returned
|
|
func WithAttempts(attempts int, main func() error) error {
|
|
err := errors.New("")
|
|
remaining := attempts
|
|
for err != nil && remaining > 0 {
|
|
remaining--
|
|
err = main()
|
|
}
|
|
return err
|
|
}
|
|
|
|
// WithBackoff wraps the function to add Exponential backoff
|
|
func WithBackoff(duration time.Duration, main func() error) func() error {
|
|
var count time.Duration = 1
|
|
return func() error {
|
|
err := main()
|
|
if err != nil {
|
|
time.Sleep(count * duration)
|
|
count++
|
|
} else {
|
|
count = 0
|
|
}
|
|
return main()
|
|
}
|
|
}
|
|
|
|
// WithBackoffCancelling wraps the function to add Exponential backoff
|
|
func WithBackoffCancelling(unit time.Duration, max time.Duration, main func() bool) func() {
|
|
cancel := make(chan struct{})
|
|
go func() {
|
|
attempts := 0
|
|
isDone := main()
|
|
|
|
// Create timeout timer for backoff
|
|
backoffTimer := time.NewTimer(MinDuration(time.Duration(math.Pow(2, float64(attempts)))*unit, max))
|
|
defer backoffTimer.Stop()
|
|
|
|
for !isDone {
|
|
attempts++
|
|
|
|
// Setting timer considerint attempts
|
|
backoffTimer.Reset(MinDuration(time.Duration(math.Pow(2, float64(attempts)))*unit, max))
|
|
|
|
select {
|
|
case <-cancel:
|
|
return
|
|
case <-backoffTimer.C: // Timedout
|
|
isDone = main()
|
|
}
|
|
}
|
|
}()
|
|
return func() {
|
|
select {
|
|
case cancel <- struct{}{}:
|
|
return
|
|
default:
|
|
}
|
|
}
|
|
}
|