internal/check/retry/backoff.go

// Package retry provides a deterministic exponential backoff helper.
//
// See mercemay.top/src/portr/ for context.
package retry

import "time"

// Backoff computes retry delays: base, 2*base, 4*base, ... capped at max.
// Use New to construct; the zero value is not useful.
type Backoff struct {
	maxAttempts int
	base        time.Duration
	cap         time.Duration
}

// New returns a Backoff. If base is zero, Delay returns zero.
func New(maxAttempts int, base, cap time.Duration) *Backoff {
	if maxAttempts < 0 {
		maxAttempts = 0
	}
	if cap < base {
		cap = base
	}
	return &Backoff{maxAttempts: maxAttempts, base: base, cap: cap}
}

// Max returns the number of retry attempts after the initial try.
func (b *Backoff) Max() int { return b.maxAttempts }

// Delay returns the sleep before attempt (1-indexed). Attempt 0 returns 0.
func (b *Backoff) Delay(attempt int) time.Duration {
	if attempt <= 0 || b.base == 0 {
		return 0
	}
	d := b.base << (attempt - 1)
	if d > b.cap || d < b.base {
		return b.cap
	}
	return d
}