mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2026-05-17 00:26:36 +03:00
### Describe Your Changes
I noticed that the backoff timer logic is repeated across multiple
packages. I've implemented a universal wrapper to avoid duplicating this
logic. This structure is already [actively
used](2aa0ea10bb/app/vlagent/kubernetescollector/backoff_timer.go (L11))
for the Kubernetes Collector in vlagent and can be reused in vlagent's
remotewrite. I've also included a usage example in this PR so you can
evaluate its utility.
### Checklist
The following checks are **mandatory**:
- [X] My change adheres to [VictoriaMetrics contributing
guidelines](https://docs.victoriametrics.com/victoriametrics/contributing/#pull-request-checklist).
- [X] My change adheres to [VictoriaMetrics development
goals](https://docs.victoriametrics.com/victoriametrics/goals/).
69 lines
1.5 KiB
Go
69 lines
1.5 KiB
Go
package timeutil
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/timerpool"
|
|
)
|
|
|
|
// BackoffTimer implements an exponential backoff timer with jitter.
|
|
type BackoffTimer struct {
|
|
min time.Duration
|
|
max time.Duration
|
|
current time.Duration
|
|
}
|
|
|
|
// NewBackoffTimer returns a new BackoffTimer initialized with the given minDelay and maxDelay.
|
|
func NewBackoffTimer(minDelay, maxDelay time.Duration) *BackoffTimer {
|
|
if maxDelay < minDelay {
|
|
minDelay = maxDelay
|
|
}
|
|
return &BackoffTimer{
|
|
min: minDelay,
|
|
max: maxDelay,
|
|
current: minDelay,
|
|
}
|
|
}
|
|
|
|
// Wait sleeps for the current delay with jitter, doubling the delay for the next Wait.
|
|
// Use CurrentDelay to get the current backoff duration.
|
|
//
|
|
// Wait returns false if stopCh is closed.
|
|
func (bt *BackoffTimer) Wait(stopCh <-chan struct{}) bool {
|
|
v := AddJitterToDuration(bt.current)
|
|
bt.current *= 2
|
|
if bt.current > bt.max {
|
|
bt.current = bt.max
|
|
}
|
|
|
|
timer := timerpool.Get(v)
|
|
defer timerpool.Put(timer)
|
|
select {
|
|
case <-stopCh:
|
|
return false
|
|
case <-timer.C:
|
|
return true
|
|
}
|
|
}
|
|
|
|
// CurrentDelay returns the current backoff duration.
|
|
func (bt *BackoffTimer) CurrentDelay() time.Duration {
|
|
return bt.current
|
|
}
|
|
|
|
// SetDelay overrides the current delay. Useful for respecting Retry-After headers.
|
|
func (bt *BackoffTimer) SetDelay(d time.Duration) {
|
|
if d < bt.min {
|
|
d = bt.min
|
|
}
|
|
if d > bt.max {
|
|
d = bt.max
|
|
}
|
|
bt.current = d
|
|
}
|
|
|
|
// Reset sets the backoff delay to its minimum.
|
|
func (bt *BackoffTimer) Reset() {
|
|
bt.current = bt.min
|
|
}
|