-
Notifications
You must be signed in to change notification settings - Fork 93
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DefaultClientRetryPolicy overflows to past #697
Comments
I looked into this a bit, and although I couldn't get the next retry time to overflow, there are some oddities around handling of very large durations that we should at least be explicit about it. The maximum length of the time that can be stored in a duration is about 292 years, and once you start going over that, you're in danger of overflowing it and can get some odd behavior. I'm not sure how you even got there though. You start hit duration limits at retry 310, but before 310 you're already well into exponential territory, so you'll never actually be hitting those next retries because they're 100s of years out. I see that you got to attempt no. 305 in your record above, but if you using the default policy isn't the distance between attempt 304 and 305 still measured in months? |
… counts This one's here to address #697, where's it been reported that it may be possible for retry schedules to overflow to the past when reaching degenerately high numbers of attempts. I couldn't reproduce the reported problem, but it is possible for `time.Duration` to overflow, so here we shore up `DefaultClientRetryPolicy` so that we're explicitly defining what behavior should occur under these conditions. The maximum length of time that can go in a `time.Duration` is about 292 years. Here's a sample program that demonstrates an overflow happening: func main() { const maxDuration time.Duration = 1<<63 - 1 var maxDurationSeconds = float64(maxDuration / time.Second) notOverflowed := time.Duration(maxDurationSeconds) * time.Second fmt.Printf("not overflowed: %+v\n", notOverflowed) overflowed := time.Duration(maxDurationSeconds+1) * time.Second fmt.Printf("overflowed: %+v\n", overflowed) } not overflowed: 2562047h47m16s overflowed: -2562047h47m16.709551616s Here, modify `DefaultClientRetryPolicy` so that if it were to return a next retry duration greater than what would fit in `time.Duration`, we just return 292 years instead. The maximum bound occurs at 310 retries, so every retry after 310 increments by 292 years. I didn't bother putting a maximum bound on the time returned by `NextRetry` because the maximum `time.Time` in Go is somewhere in the year 219250468, so even in 292 year increments, you'll never get there.
… counts This one's here to address #697, where's it been reported that it may be possible for retry schedules to overflow to the past when reaching degenerately high numbers of attempts. I couldn't reproduce the reported problem, but it is possible for `time.Duration` to overflow, so here we shore up `DefaultClientRetryPolicy` so that we're explicitly defining what behavior should occur under these conditions. The maximum length of time that can go in a `time.Duration` is about 292 years. Here's a sample program that demonstrates an overflow happening: func main() { const maxDuration time.Duration = 1<<63 - 1 var maxDurationSeconds = float64(maxDuration / time.Second) notOverflowed := time.Duration(maxDurationSeconds) * time.Second fmt.Printf("not overflowed: %+v\n", notOverflowed) overflowed := time.Duration(maxDurationSeconds+1) * time.Second fmt.Printf("overflowed: %+v\n", overflowed) } not overflowed: 2562047h47m16s overflowed: -2562047h47m16.709551616s Here, modify `DefaultClientRetryPolicy` so that if it were to return a next retry duration greater than what would fit in `time.Duration`, we just return 292 years instead. The maximum bound occurs at 310 retries, so every retry after 310 increments by 292 years. I didn't bother putting a maximum bound on the time returned by `NextRetry` because the maximum `time.Time` in Go is somewhere in the year 219250468, so even in 292 year increments, you'll never get there.
Added #698 to make sure we never overflow |
… counts This one's here to address #697, where's it been reported that it may be possible for retry schedules to overflow to the past when reaching degenerately high numbers of attempts. I couldn't reproduce the reported problem, but it is possible for `time.Duration` to overflow, so here we shore up `DefaultClientRetryPolicy` so that we're explicitly defining what behavior should occur under these conditions. The maximum length of time that can go in a `time.Duration` is about 292 years. Here's a sample program that demonstrates an overflow happening: func main() { const maxDuration time.Duration = 1<<63 - 1 var maxDurationSeconds = float64(maxDuration / time.Second) notOverflowed := time.Duration(maxDurationSeconds) * time.Second fmt.Printf("not overflowed: %+v\n", notOverflowed) overflowed := time.Duration(maxDurationSeconds+1) * time.Second fmt.Printf("overflowed: %+v\n", overflowed) } not overflowed: 2562047h47m16s overflowed: -2562047h47m16.709551616s Here, modify `DefaultClientRetryPolicy` so that if it were to return a next retry duration greater than what would fit in `time.Duration`, we just return 292 years instead. The maximum bound occurs at 310 retries, so every retry after 310 increments by 292 years. I didn't bother putting a maximum bound on the time returned by `NextRetry` because the maximum `time.Time` in Go is somewhere in the year 219250468, so even in 292 year increments, you'll never get there.
… counts (#698) This one's here to address #697, where's it been reported that it may be possible for retry schedules to overflow to the past when reaching degenerately high numbers of attempts. I couldn't reproduce the reported problem, but it is possible for `time.Duration` to overflow, so here we shore up `DefaultClientRetryPolicy` so that we're explicitly defining what behavior should occur under these conditions. The maximum length of time that can go in a `time.Duration` is about 292 years. Here's a sample program that demonstrates an overflow happening: func main() { const maxDuration time.Duration = 1<<63 - 1 var maxDurationSeconds = float64(maxDuration / time.Second) notOverflowed := time.Duration(maxDurationSeconds) * time.Second fmt.Printf("not overflowed: %+v\n", notOverflowed) overflowed := time.Duration(maxDurationSeconds+1) * time.Second fmt.Printf("overflowed: %+v\n", overflowed) } not overflowed: 2562047h47m16s overflowed: -2562047h47m16.709551616s Here, modify `DefaultClientRetryPolicy` so that if it were to return a next retry duration greater than what would fit in `time.Duration`, we just return 292 years instead. The maximum bound occurs at 310 retries, so every retry after 310 increments by 292 years. I didn't bother putting a maximum bound on the time returned by `NextRetry` because the maximum `time.Time` in Go is somewhere in the year 219250468, so even in 292 year increments, you'll never get there.
In retry mechanism, if we increase
MaxAttempts
, thenDefaultClientRetryPolicy
will overflow at some point andNextRetry()
will return a date in the past:UPD: changed the previous hypothesis.
It seems that it only overflows in the logs, where conversion to Unix time happens.
I checked the database and the date is fine:
But then I also don't understand why our custom policy that is designed to cap retry time doesn't work. Here's the code:
With this policy we still get retry time that is far beyond our threshold (such as in the logs above).
The text was updated successfully, but these errors were encountered: