implement a new backoff abstraction (#75)

This commit is contained in:
Pat Whittingslow
2026-04-14 16:11:03 -03:00
committed by GitHub
parent 191b8ee4cc
commit 5bde7a9979
5 changed files with 100 additions and 86 deletions
+11 -56
View File
@@ -2,61 +2,16 @@ package internal
import "time"
type BackoffFlags uint8
const (
BackoffHasPriority BackoffFlags = 1 << iota
BackoffCriticalPath
BackoffTCPConn
)
const backoffMinWait = time.Microsecond
func backoffMaxWait(priority BackoffFlags) time.Duration {
switch {
case priority&BackoffCriticalPath != 0:
return 1 * time.Millisecond
case priority&BackoffTCPConn != 0:
return 5 * time.Millisecond
default:
return time.Second >> (priority & BackoffHasPriority)
}
}
func NewBackoff(priority BackoffFlags) Backoff {
return Backoff{
wait: uint32(backoffMinWait),
maxWait: uint32(backoffMaxWait(priority)),
startWait: uint32(backoffMinWait),
}
}
// A Backoff with a non-zero MaxWait is ready for use.
type Backoff struct {
// wait defines the amount of time that Miss will wait on next call.
wait uint32
// Maximum allowable value for Wait.
maxWait uint32
// startWait is the intial Wait value, as well as the value that Wait takes after a call to Hit.
startWait uint32
}
// Hit sets eb.Wait to the StartWait value.
func (eb *Backoff) Hit() {
if eb.maxWait == 0 {
panic("MaxWait cannot be zero")
}
eb.wait = eb.startWait
}
// Miss sleeps for eb.Wait and increases eb.Wait exponentially.
func (eb *Backoff) Miss() {
if eb.maxWait == 0 {
panic("MaxWait cannot be zero")
}
time.Sleep(time.Duration(eb.wait))
eb.wait *= 2
if eb.wait > eb.maxWait {
eb.wait = eb.maxWait
// ConnRWBackoff implements exponential backoff suitable for TCP connection
// read/write polling. It starts at 1us and caps at 5ms, doubling on each consecutive backoff.
func ConnRWBackoff(consecutiveBackoffs int) {
const (
minWait = time.Microsecond >> 1
maxWait = 5 * time.Millisecond
)
wait := minWait << consecutiveBackoffs
if wait > maxWait {
wait = maxWait
}
time.Sleep(wait)
}