67 lines
2.6 KiB
Go
67 lines
2.6 KiB
Go
// Copyright (c) 2015-2021 MinIO, Inc.
|
|
//
|
|
// This file is part of MinIO Object Storage stack
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
package crypto
|
|
|
|
import (
|
|
"math/rand"
|
|
"time"
|
|
)
|
|
|
|
// default retry configuration
|
|
const (
|
|
retryWaitMin = 100 * time.Millisecond // minimum retry limit.
|
|
retryWaitMax = 1500 * time.Millisecond // 1.5 secs worth of max retry.
|
|
)
|
|
|
|
// LinearJitterBackoff provides the time.Duration for a caller to
|
|
// perform linear backoff based on the attempt number and with jitter to
|
|
// prevent a thundering herd.
|
|
//
|
|
// min and max here are *not* absolute values. The number to be multiplied by
|
|
// the attempt number will be chosen at random from between them, thus they are
|
|
// bounding the jitter.
|
|
//
|
|
// For instance:
|
|
// * To get strictly linear backoff of one second increasing each retry, set
|
|
// both to one second (1s, 2s, 3s, 4s, ...)
|
|
// * To get a small amount of jitter centered around one second increasing each
|
|
// retry, set to around one second, such as a min of 800ms and max of 1200ms
|
|
// (892ms, 2102ms, 2945ms, 4312ms, ...)
|
|
// * To get extreme jitter, set to a very wide spread, such as a min of 100ms
|
|
// and a max of 20s (15382ms, 292ms, 51321ms, 35234ms, ...)
|
|
func LinearJitterBackoff(min, max time.Duration, attemptNum int) time.Duration {
|
|
// attemptNum always starts at zero but we want to start at 1 for multiplication
|
|
attemptNum++
|
|
|
|
if max <= min {
|
|
// Unclear what to do here, or they are the same, so return min *
|
|
// attemptNum
|
|
return min * time.Duration(attemptNum)
|
|
}
|
|
|
|
// Seed rand; doing this every time is fine
|
|
rand := rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
|
|
|
|
// Pick a random number that lies somewhere between the min and max and
|
|
// multiply by the attemptNum. attemptNum starts at zero so we always
|
|
// increment here. We first get a random percentage, then apply that to the
|
|
// difference between min and max, and add to min.
|
|
jitter := rand.Float64() * float64(max-min)
|
|
jitterMin := int64(jitter) + int64(min)
|
|
return time.Duration(jitterMin * int64(attemptNum))
|
|
}
|