Goback implements a simple exponential backoff.
An exponential backoff approach is typically used when treating with potentially faulty/slow systems. If a system fails quick retries may exacerbate the system specially when the system is dealing with several clients. In this case a backoff provides the faulty system enough room to recover.
func main() {
b, err := exponential.New(
exponential.WithMinimum(100*time.Millisecond),
exponential.WithMaximum(60*time.Second),
exponential.WithFactor(2),
)
if err != nil {
panic(err)
}
backoff.Wait(b) // sleeps 100ms
backoff.Wait(b) // sleeps 200ms
backoff.Wait(b) // sleeps 400ms
fmt.Println(b.NextDuration()) // prints 800ms
b.Reset() // resets the backoff
backoff.Wait(b) // sleeps 100ms
}Further examples can be found in the examples folder.
At the moment there are four backoff implementations.
This is a backoff implementation that will always return zero values for NextDuration.
This is a backoff implementation that will always return the given value for NextDuration.
It starts with a minumum duration and multiplies it by the factor until the maximum waiting time is reached. In that case it will return Maximum.
The optional Limit will limit the maximum number of retries and will return an error when is exceeded.
The Jitter strategy leverages a provided backoff implementation but adds a light randomisation to minimise collisions between contending clients.
By creating structs that implement the methods of the Backoff interface you will be able to use them as a backoff strategy.
A naive example of this is:
type NaiveBackoff struct{}
func (b *NaiveBackoff) NextAttempt() (time.Duration, error) { return time.Second, nil }
func (b *NaiveBackoff) Reset() { }This will return always a 1s duration.
This package is based on https://github.com/carlescere/goback with a larger focus on implementations having more of a single purpose and leveraging composition to layer desired behavior of the resulting structure.