storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/crypto/retry.go (about)

     1  // MinIO Cloud Storage, (C) 2020 MinIO, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package crypto
    16  
    17  import (
    18  	"math/rand"
    19  	"time"
    20  )
    21  
    22  // default retry configuration
    23  const (
    24  	retryWaitMin = 100 * time.Millisecond  // minimum retry limit.
    25  	retryWaitMax = 1500 * time.Millisecond // 1.5 secs worth of max retry.
    26  )
    27  
    28  // LinearJitterBackoff provides the time.Duration for a caller to
    29  // perform linear backoff based on the attempt number and with jitter to
    30  // prevent a thundering herd.
    31  //
    32  // min and max here are *not* absolute values. The number to be multiplied by
    33  // the attempt number will be chosen at random from between them, thus they are
    34  // bounding the jitter.
    35  //
    36  // For instance:
    37  // * To get strictly linear backoff of one second increasing each retry, set
    38  // both to one second (1s, 2s, 3s, 4s, ...)
    39  // * To get a small amount of jitter centered around one second increasing each
    40  // retry, set to around one second, such as a min of 800ms and max of 1200ms
    41  // (892ms, 2102ms, 2945ms, 4312ms, ...)
    42  // * To get extreme jitter, set to a very wide spread, such as a min of 100ms
    43  // and a max of 20s (15382ms, 292ms, 51321ms, 35234ms, ...)
    44  func LinearJitterBackoff(min, max time.Duration, attemptNum int) time.Duration {
    45  	// attemptNum always starts at zero but we want to start at 1 for multiplication
    46  	attemptNum++
    47  
    48  	if max <= min {
    49  		// Unclear what to do here, or they are the same, so return min *
    50  		// attemptNum
    51  		return min * time.Duration(attemptNum)
    52  	}
    53  
    54  	// Seed rand; doing this every time is fine
    55  	rand := rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
    56  
    57  	// Pick a random number that lies somewhere between the min and max and
    58  	// multiply by the attemptNum. attemptNum starts at zero so we always
    59  	// increment here. We first get a random percentage, then apply that to the
    60  	// difference between min and max, and add to min.
    61  	jitter := rand.Float64() * float64(max-min)
    62  	jitterMin := int64(jitter) + int64(min)
    63  	return time.Duration(jitterMin * int64(attemptNum))
    64  }