k8s.io/client-go@v0.31.1/util/workqueue/default_rate_limiters.go (about)

     1  /*
     2  Copyright 2016 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package workqueue
    18  
    19  import (
    20  	"math"
    21  	"sync"
    22  	"time"
    23  
    24  	"golang.org/x/time/rate"
    25  )
    26  
    27  // Deprecated: RateLimiter is deprecated, use TypedRateLimiter instead.
    28  type RateLimiter TypedRateLimiter[any]
    29  
    30  type TypedRateLimiter[T comparable] interface {
    31  	// When gets an item and gets to decide how long that item should wait
    32  	When(item T) time.Duration
    33  	// Forget indicates that an item is finished being retried.  Doesn't matter whether it's for failing
    34  	// or for success, we'll stop tracking it
    35  	Forget(item T)
    36  	// NumRequeues returns back how many failures the item has had
    37  	NumRequeues(item T) int
    38  }
    39  
    40  // DefaultControllerRateLimiter is a no-arg constructor for a default rate limiter for a workqueue.  It has
    41  // both overall and per-item rate limiting.  The overall is a token bucket and the per-item is exponential
    42  //
    43  // Deprecated: Use DefaultTypedControllerRateLimiter instead.
    44  func DefaultControllerRateLimiter() RateLimiter {
    45  	return DefaultTypedControllerRateLimiter[any]()
    46  }
    47  
    48  // DefaultTypedControllerRateLimiter is a no-arg constructor for a default rate limiter for a workqueue.  It has
    49  // both overall and per-item rate limiting.  The overall is a token bucket and the per-item is exponential
    50  func DefaultTypedControllerRateLimiter[T comparable]() TypedRateLimiter[T] {
    51  	return NewTypedMaxOfRateLimiter(
    52  		NewTypedItemExponentialFailureRateLimiter[T](5*time.Millisecond, 1000*time.Second),
    53  		// 10 qps, 100 bucket size.  This is only for retry speed and its only the overall factor (not per item)
    54  		&TypedBucketRateLimiter[T]{Limiter: rate.NewLimiter(rate.Limit(10), 100)},
    55  	)
    56  }
    57  
    58  // Deprecated: BucketRateLimiter is deprecated, use TypedBucketRateLimiter instead.
    59  type BucketRateLimiter = TypedBucketRateLimiter[any]
    60  
    61  // TypedBucketRateLimiter adapts a standard bucket to the workqueue ratelimiter API
    62  type TypedBucketRateLimiter[T comparable] struct {
    63  	*rate.Limiter
    64  }
    65  
    66  var _ RateLimiter = &BucketRateLimiter{}
    67  
    68  func (r *TypedBucketRateLimiter[T]) When(item T) time.Duration {
    69  	return r.Limiter.Reserve().Delay()
    70  }
    71  
    72  func (r *TypedBucketRateLimiter[T]) NumRequeues(item T) int {
    73  	return 0
    74  }
    75  
    76  func (r *TypedBucketRateLimiter[T]) Forget(item T) {
    77  }
    78  
    79  // Deprecated: ItemExponentialFailureRateLimiter is deprecated, use TypedItemExponentialFailureRateLimiter instead.
    80  type ItemExponentialFailureRateLimiter = TypedItemExponentialFailureRateLimiter[any]
    81  
    82  // TypedItemExponentialFailureRateLimiter does a simple baseDelay*2^<num-failures> limit
    83  // dealing with max failures and expiration are up to the caller
    84  type TypedItemExponentialFailureRateLimiter[T comparable] struct {
    85  	failuresLock sync.Mutex
    86  	failures     map[T]int
    87  
    88  	baseDelay time.Duration
    89  	maxDelay  time.Duration
    90  }
    91  
    92  var _ RateLimiter = &ItemExponentialFailureRateLimiter{}
    93  
    94  // Deprecated: NewItemExponentialFailureRateLimiter is deprecated, use NewTypedItemExponentialFailureRateLimiter instead.
    95  func NewItemExponentialFailureRateLimiter(baseDelay time.Duration, maxDelay time.Duration) RateLimiter {
    96  	return NewTypedItemExponentialFailureRateLimiter[any](baseDelay, maxDelay)
    97  }
    98  
    99  func NewTypedItemExponentialFailureRateLimiter[T comparable](baseDelay time.Duration, maxDelay time.Duration) TypedRateLimiter[T] {
   100  	return &TypedItemExponentialFailureRateLimiter[T]{
   101  		failures:  map[T]int{},
   102  		baseDelay: baseDelay,
   103  		maxDelay:  maxDelay,
   104  	}
   105  }
   106  
   107  // Deprecated: DefaultItemBasedRateLimiter is deprecated, use DefaultTypedItemBasedRateLimiter instead.
   108  func DefaultItemBasedRateLimiter() RateLimiter {
   109  	return DefaultTypedItemBasedRateLimiter[any]()
   110  }
   111  
   112  func DefaultTypedItemBasedRateLimiter[T comparable]() TypedRateLimiter[T] {
   113  	return NewTypedItemExponentialFailureRateLimiter[T](time.Millisecond, 1000*time.Second)
   114  }
   115  
   116  func (r *TypedItemExponentialFailureRateLimiter[T]) When(item T) time.Duration {
   117  	r.failuresLock.Lock()
   118  	defer r.failuresLock.Unlock()
   119  
   120  	exp := r.failures[item]
   121  	r.failures[item] = r.failures[item] + 1
   122  
   123  	// The backoff is capped such that 'calculated' value never overflows.
   124  	backoff := float64(r.baseDelay.Nanoseconds()) * math.Pow(2, float64(exp))
   125  	if backoff > math.MaxInt64 {
   126  		return r.maxDelay
   127  	}
   128  
   129  	calculated := time.Duration(backoff)
   130  	if calculated > r.maxDelay {
   131  		return r.maxDelay
   132  	}
   133  
   134  	return calculated
   135  }
   136  
   137  func (r *TypedItemExponentialFailureRateLimiter[T]) NumRequeues(item T) int {
   138  	r.failuresLock.Lock()
   139  	defer r.failuresLock.Unlock()
   140  
   141  	return r.failures[item]
   142  }
   143  
   144  func (r *TypedItemExponentialFailureRateLimiter[T]) Forget(item T) {
   145  	r.failuresLock.Lock()
   146  	defer r.failuresLock.Unlock()
   147  
   148  	delete(r.failures, item)
   149  }
   150  
   151  // ItemFastSlowRateLimiter does a quick retry for a certain number of attempts, then a slow retry after that
   152  // Deprecated: Use TypedItemFastSlowRateLimiter instead.
   153  type ItemFastSlowRateLimiter = TypedItemFastSlowRateLimiter[any]
   154  
   155  // TypedItemFastSlowRateLimiter does a quick retry for a certain number of attempts, then a slow retry after that
   156  type TypedItemFastSlowRateLimiter[T comparable] struct {
   157  	failuresLock sync.Mutex
   158  	failures     map[T]int
   159  
   160  	maxFastAttempts int
   161  	fastDelay       time.Duration
   162  	slowDelay       time.Duration
   163  }
   164  
   165  var _ RateLimiter = &ItemFastSlowRateLimiter{}
   166  
   167  // Deprecated: NewItemFastSlowRateLimiter is deprecated, use NewTypedItemFastSlowRateLimiter instead.
   168  func NewItemFastSlowRateLimiter(fastDelay, slowDelay time.Duration, maxFastAttempts int) RateLimiter {
   169  	return NewTypedItemFastSlowRateLimiter[any](fastDelay, slowDelay, maxFastAttempts)
   170  }
   171  
   172  func NewTypedItemFastSlowRateLimiter[T comparable](fastDelay, slowDelay time.Duration, maxFastAttempts int) TypedRateLimiter[T] {
   173  	return &TypedItemFastSlowRateLimiter[T]{
   174  		failures:        map[T]int{},
   175  		fastDelay:       fastDelay,
   176  		slowDelay:       slowDelay,
   177  		maxFastAttempts: maxFastAttempts,
   178  	}
   179  }
   180  
   181  func (r *TypedItemFastSlowRateLimiter[T]) When(item T) time.Duration {
   182  	r.failuresLock.Lock()
   183  	defer r.failuresLock.Unlock()
   184  
   185  	r.failures[item] = r.failures[item] + 1
   186  
   187  	if r.failures[item] <= r.maxFastAttempts {
   188  		return r.fastDelay
   189  	}
   190  
   191  	return r.slowDelay
   192  }
   193  
   194  func (r *TypedItemFastSlowRateLimiter[T]) NumRequeues(item T) int {
   195  	r.failuresLock.Lock()
   196  	defer r.failuresLock.Unlock()
   197  
   198  	return r.failures[item]
   199  }
   200  
   201  func (r *TypedItemFastSlowRateLimiter[T]) Forget(item T) {
   202  	r.failuresLock.Lock()
   203  	defer r.failuresLock.Unlock()
   204  
   205  	delete(r.failures, item)
   206  }
   207  
   208  // MaxOfRateLimiter calls every RateLimiter and returns the worst case response
   209  // When used with a token bucket limiter, the burst could be apparently exceeded in cases where particular items
   210  // were separately delayed a longer time.
   211  //
   212  // Deprecated: Use TypedMaxOfRateLimiter instead.
   213  type MaxOfRateLimiter = TypedMaxOfRateLimiter[any]
   214  
   215  // TypedMaxOfRateLimiter calls every RateLimiter and returns the worst case response
   216  // When used with a token bucket limiter, the burst could be apparently exceeded in cases where particular items
   217  // were separately delayed a longer time.
   218  type TypedMaxOfRateLimiter[T comparable] struct {
   219  	limiters []TypedRateLimiter[T]
   220  }
   221  
   222  func (r *TypedMaxOfRateLimiter[T]) When(item T) time.Duration {
   223  	ret := time.Duration(0)
   224  	for _, limiter := range r.limiters {
   225  		curr := limiter.When(item)
   226  		if curr > ret {
   227  			ret = curr
   228  		}
   229  	}
   230  
   231  	return ret
   232  }
   233  
   234  // Deprecated: NewMaxOfRateLimiter is deprecated, use NewTypedMaxOfRateLimiter instead.
   235  func NewMaxOfRateLimiter(limiters ...TypedRateLimiter[any]) RateLimiter {
   236  	return NewTypedMaxOfRateLimiter(limiters...)
   237  }
   238  
   239  func NewTypedMaxOfRateLimiter[T comparable](limiters ...TypedRateLimiter[T]) TypedRateLimiter[T] {
   240  	return &TypedMaxOfRateLimiter[T]{limiters: limiters}
   241  }
   242  
   243  func (r *TypedMaxOfRateLimiter[T]) NumRequeues(item T) int {
   244  	ret := 0
   245  	for _, limiter := range r.limiters {
   246  		curr := limiter.NumRequeues(item)
   247  		if curr > ret {
   248  			ret = curr
   249  		}
   250  	}
   251  
   252  	return ret
   253  }
   254  
   255  func (r *TypedMaxOfRateLimiter[T]) Forget(item T) {
   256  	for _, limiter := range r.limiters {
   257  		limiter.Forget(item)
   258  	}
   259  }
   260  
   261  // WithMaxWaitRateLimiter have maxDelay which avoids waiting too long
   262  // Deprecated: Use TypedWithMaxWaitRateLimiter instead.
   263  type WithMaxWaitRateLimiter = TypedWithMaxWaitRateLimiter[any]
   264  
   265  // TypedWithMaxWaitRateLimiter have maxDelay which avoids waiting too long
   266  type TypedWithMaxWaitRateLimiter[T comparable] struct {
   267  	limiter  TypedRateLimiter[T]
   268  	maxDelay time.Duration
   269  }
   270  
   271  // Deprecated: NewWithMaxWaitRateLimiter is deprecated, use NewTypedWithMaxWaitRateLimiter instead.
   272  func NewWithMaxWaitRateLimiter(limiter RateLimiter, maxDelay time.Duration) RateLimiter {
   273  	return NewTypedWithMaxWaitRateLimiter[any](limiter, maxDelay)
   274  }
   275  
   276  func NewTypedWithMaxWaitRateLimiter[T comparable](limiter TypedRateLimiter[T], maxDelay time.Duration) TypedRateLimiter[T] {
   277  	return &TypedWithMaxWaitRateLimiter[T]{limiter: limiter, maxDelay: maxDelay}
   278  }
   279  
   280  func (w TypedWithMaxWaitRateLimiter[T]) When(item T) time.Duration {
   281  	delay := w.limiter.When(item)
   282  	if delay > w.maxDelay {
   283  		return w.maxDelay
   284  	}
   285  
   286  	return delay
   287  }
   288  
   289  func (w TypedWithMaxWaitRateLimiter[T]) Forget(item T) {
   290  	w.limiter.Forget(item)
   291  }
   292  
   293  func (w TypedWithMaxWaitRateLimiter[T]) NumRequeues(item T) int {
   294  	return w.limiter.NumRequeues(item)
   295  }