Skip to content

Commit

Permalink
Add default provider and controller rate limiters
Browse files Browse the repository at this point in the history
Adds default rate limiters to be used at both the provider and
controller level. The provider rate limiter is a configurable token
bucket and the controller limiter is a max of limiter that uses the
provider limiter and a per-item exponential backoff.

Signed-off-by: hasheddan <[email protected]>
  • Loading branch information
hasheddan committed Feb 15, 2021
1 parent b7b3de9 commit 071c193
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 0 deletions.
48 changes: 48 additions & 0 deletions pkg/ratelimiter/default.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
Copyright 2021 The Crossplane Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package ratelimiter

import (
"time"

"golang.org/x/time/rate"
"k8s.io/client-go/util/workqueue"
"sigs.k8s.io/controller-runtime/pkg/ratelimiter"
)

// DefaultProviderRPS is the recommended default average requeues per second
// tolerated by a provider's controller manager.
const DefaultProviderRPS = 1

// NewDefaultProviderRateLimiter returns a token bucket rate limiter meant for
// limiting the number of average total requeues per second for all controllers
// registered with a controller manager. The bucket size is a linear function of
// the requeues per second.
func NewDefaultProviderRateLimiter(rps int) *workqueue.BucketRateLimiter {
return &workqueue.BucketRateLimiter{Limiter: rate.NewLimiter(rate.Limit(rps), rps*10)}
}

// NewDefaultManagedRateLimiter returns a rate limiter that takes the maximum
// delay between the passed providerRateLimiter and a per-item exponential
// backoff limiter. The exponential backoff limiter has a base delay of 1s and a
// maximum of 60s.
func NewDefaultManagedRateLimiter(providerRateLimiter ratelimiter.RateLimiter) ratelimiter.RateLimiter {
return workqueue.NewMaxOfRateLimiter(
workqueue.NewItemExponentialFailureRateLimiter(1*time.Second, 60*time.Second),
providerRateLimiter,
)
}
42 changes: 42 additions & 0 deletions pkg/ratelimiter/default_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
Copyright 2021 The Crossplane Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package ratelimiter

import (
"sync"
"testing"
"time"
)

func TestDefaultMangedRateLimiter(t *testing.T) {
limiter := NewDefaultManagedRateLimiter(NewDefaultProviderRateLimiter(DefaultProviderRPS))
backoffSchedule := []int{1, 2, 4, 8, 16, 32, 60}
for _, d := range backoffSchedule {
if e, a := time.Duration(d)*time.Second, limiter.When("one"); e != a {
t.Errorf("expected %v, got %v", e, a)
}
}
limiter.Forget("one")
if e, a := time.Duration(backoffSchedule[0])*time.Second, limiter.When("one"); e != a {
t.Errorf("expected %v, got %v", e, a)
}
wg := &sync.WaitGroup{}
wg.Add(1)
go func() {
wg.Done()
}()
}

0 comments on commit 071c193

Please sign in to comment.