fleet/pkg/retry/retry.go
Lucas Manuel Rodriguez e9a464e0cf
Add exponential backoff to orbit enroll retries (#17368)
#16594

- [X] Changes file added for user-visible changes in `changes/` or
`orbit/changes/`.
See [Changes
files](https://fleetdm.com/docs/contributing/committing-changes#changes-files)
for more information.
- [X] Added/updated tests
- [X] Manual QA for all new/changed functionality
  - For Orbit and Fleet Desktop changes:
- [X] Manual QA must be performed in the three main OSs, macOS, Windows
and Linux.
- [X] Auto-update manual QA, from released version of component to new
version (see [tools/tuf/test](../tools/tuf/test/README.md)).
2024-03-13 07:57:00 -03:00

79 lines
1.6 KiB
Go

// Package retry has utilities to retry operations.
package retry
import (
"time"
)
type config struct {
initialInterval time.Duration
backoffMultiplier int
maxAttempts int
}
// Option allows to configure the behavior of retry.Do
type Option func(*config)
// WithInterval allows to specify a custom duration to wait
// between retries.
func WithInterval(i time.Duration) Option {
return func(c *config) {
c.initialInterval = i
}
}
// WithBackoffMultiplier allows to specify the backoff multiplier between retries.
func WithBackoffMultiplier(m int) Option {
return func(c *config) {
c.backoffMultiplier = m
}
}
// WithMaxAttempts allows to specify a maximum number of attempts
// before the doer gives up.
func WithMaxAttempts(a int) Option {
return func(c *config) {
c.maxAttempts = a
}
}
// Do executes the provided function, if the function returns a
// non-nil error it performs a retry according to the options
// provided.
//
// By default operations are retried an unlimited number of times for 30
// seconds
func Do(fn func() error, opts ...Option) error {
cfg := &config{
initialInterval: 30 * time.Second,
}
for _, opt := range opts {
opt(cfg)
}
attempts := 0
ticker := time.NewTicker(cfg.initialInterval)
defer ticker.Stop()
backoff := 1
for {
attempts++
err := fn()
if err == nil {
return nil
}
if cfg.maxAttempts != 0 && attempts >= cfg.maxAttempts {
return err
}
if cfg.backoffMultiplier != 0 {
interval := time.Duration(backoff) * cfg.initialInterval
backoff *= cfg.backoffMultiplier
ticker.Reset(interval)
}
<-ticker.C
}
}