Remove unnecessary Retry.Last method, and improve the documentation

This commit is contained in:
Joseph Cumines 2024-01-24 22:21:44 +10:00
parent a8722a14a5
commit c58aede9a8
2 changed files with 19 additions and 21 deletions

View File

@ -4,12 +4,10 @@ import (
"time" "time"
) )
// Retry extends Backoff to provide a simpler, higher-level API, for // Retry extends [Backoff] to provide a simpler, higher-level API, for
// implementing exponential backoff/retry logic. // implementing exponential backoff/retry logic.
// //
// It is not safe to use concurrently. Additionally, mutating the Backoff // It is not safe to use concurrently.
// or Next fields directly may have unintended consequences, e.g. affecting the
// Last value.
type Retry struct { type Retry struct {
// Backoff is the internal [Backoff]. // Backoff is the internal [Backoff].
Backoff *Backoff Backoff *Backoff
@ -17,8 +15,7 @@ type Retry struct {
// Next is the next allowed time. As that suggests, it is set on // Next is the next allowed time. As that suggests, it is set on
// [Retry.Allow], each time an attempt is allowed. // [Retry.Allow], each time an attempt is allowed.
// Another attempt will be allowed if Next is a time <= now, or the zero // Another attempt will be allowed if Next is a time <= now, or the zero
// value. Mutating this field directly may cause unexpected behavior, // value.
// use [Retry.Reset], instead.
Next time.Time Next time.Time
} }
@ -27,7 +24,8 @@ var timeNow = time.Now // monkey patchable for testing
// Allow acts as a limiter, returning the next allowed time, or `time.Time{}`, // Allow acts as a limiter, returning the next allowed time, or `time.Time{}`,
// if the next attempt should commence, inclusive of the first attempt. // if the next attempt should commence, inclusive of the first attempt.
// If `time.Time{}` is returned, [Backoff.Duration] will be called, which will // If `time.Time{}` is returned, [Backoff.Duration] will be called, which will
// increment the [Backoff.Attempt] count, and then used to update [Retry.Next]. // increment the [Backoff.Attempt] count. The value of [Retry.Next] will be
// updated to reflect the next allowed time (the returned duration, from now).
func (x *Retry) Allow() time.Time { func (x *Retry) Allow() time.Time {
now := timeNow() now := timeNow()
if x.Next != (time.Time{}) && now.Before(x.Next) { if x.Next != (time.Time{}) && now.Before(x.Next) {
@ -37,20 +35,17 @@ func (x *Retry) Allow() time.Time {
return time.Time{} return time.Time{}
} }
// Reset resets the attempt count, and clears the next allowed time, removing // Reset resets the attempt count and clears the next allowed time, thereby
// any applied limit. // removing any applied backoff delay. This method is typically invoked after
// This method will typically be called after each success. // a successful operation. By doing so, it ensures that if a subsequent
// failure occurs, the backoff timer restarts from the minimum duration. This
// approach is useful for scenarios where intermittent issues are resolved,
// allowing the system to promptly react to new errors without being delayed
// by the increased backoff time accumulated from previous failures.
//
// Clearing the Next field directly is an alternative, that will allow the next
// attempt immediately, without resetting the attempt count.
func (x *Retry) Reset() { func (x *Retry) Reset() {
x.Backoff.Reset() x.Backoff.Reset()
x.Next = time.Time{} x.Next = time.Time{}
} }
// Last is the last time Allow was called.
//
// WARNING: Mutating the Backoff directly may cause this value to be incorrect.
func (x *Retry) Last() time.Time {
if x.Next == (time.Time{}) {
return time.Time{}
}
return x.Next.Add(-x.Backoff.ForAttempt(x.Backoff.Attempt() - 1))
}

View File

@ -122,7 +122,10 @@ func ExampleRetry_Allow_backoffBehavior() {
attemptAllowAt := func(at time.Duration) { attemptAllowAt := func(at time.Duration) {
currentAttempt := retry.Backoff.Attempt() - 1 currentAttempt := retry.Backoff.Attempt() - 1
currentBackoff := retry.Backoff.ForAttempt(currentAttempt) currentBackoff := retry.Backoff.ForAttempt(currentAttempt)
lastAttempt := retry.Last() var lastAttempt time.Time
if retry.Next != (time.Time{}) {
lastAttempt = retry.Next.Add(-retry.Backoff.ForAttempt(retry.Backoff.Attempt() - 1))
}
now := time.Unix(0, int64(at)) now := time.Unix(0, int64(at))
timeNow = func() time.Time { return now } timeNow = func() time.Time { return now }
limitedUntil := retry.Allow() limitedUntil := retry.Allow()