4 ms·
Here’s a version that’s IMO much simpler still, about half as long as both (after fixing v2’s line count cheating), and fixes a bug: both article versions wait
by handsclean 1y ago
Here’s a version that’s IMO much simpler still, about half as long as both (after fixing v2’s line count cheating), and fixes a bug: both article versions wait an extra 60 seconds between the last attempt and returning an error.
func do(ctx context.Context) error {
for attempt := 1; ; attempt++ {
if request(ctx) == nil {
return nil
}
if attempt == 10 {
return fmt.Errorf("failed after %d attempts", attempt)
}
select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(time.Second *
min(60, math.Pow(2, attempt-1)*(0.75+rand.Float64()*0.5))):
}
}
}
I think the problem with the original isn’t using a formula, it’s over-parameterization. Declaring constants right next to where they’re used once isn’t giving you anything but the opportunity for naming issues and rigidity in how you combine them. If they aren’t passed in or repeated, then I wouldn’t pull them out; if they are, then I’d try to look for minimal and natural boundary points, like just min and max, or maybe an attempt → delay function.
- Waterluvian 1y agoI sometimes agree, sometimes disagree. I don’t like magic numbers like retry(3, 1_000, 2_500) (Though sometimes your text editor and docs are good enough to help, but I don’t like making those feel required). I like how Python (and probably many other languages) allows for using the name of a positional arg. So you could call the exact same function but write it as retry(count=3, min_ms=1_000, max_ms=2_500) if you feel like it needs more clarity. Now you’ve got documented values that are tied to the function signature, their names have been decided for you, and they’re inline!
- Mawr 1y ago> Declaring constants right next to where they’re used once isn’t giving you anything but the opportunity for naming issues and rigidity in how you combine them. If they aren’t passed in or repeated, then I wouldn’t pull them out; Using magic numbers all over the place is the mark of a novice who lacks understanding that the meaning behind the numbers he knows in his mind will not magically transfer over to other people reading the code. Advising this approach is an interesting call. Specifically here, we've got these at the beginning of the function: const ( maxAttempts = 10 baseDelay = 1 * time.Second maxDelay = 60 * time.Second ) If I went out of my way to look at this function, these are probably the values I'm interested in changing, and look, they're right here, at the top. Neat. It's obvious how to adjust the values to get what I want. I can stop reading the function right there. Without these declarations, how would I know that "10" midway through the function is the number of attempts? I'd have to read and understand the entire logic first. Great. Now multiply this effort by the amount of programmers on the team and the amount of magic numbers.