Skip to content

Commit

Permalink
Explicitly set a exponential backoff rate limiter for controller config
Browse files Browse the repository at this point in the history
The rate limiter base delay and max delay values can be configured using
flags. The default values are 500ms for base delay and 15min for max delay.
  • Loading branch information
thunderboltsid committed Apr 23, 2024
1 parent 8cef217 commit db0697d
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 3 deletions.
18 changes: 17 additions & 1 deletion controllers/options.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package controllers

import "errors"
import (
"errors"

"k8s.io/client-go/util/workqueue"
)

// ControllerConfig is the configuration for cluster and machine controllers
type ControllerConfig struct {
MaxConcurrentReconciles int
RateLimiter workqueue.RateLimiter
}

// ControllerConfigOpts is a function that can be used to configure the controller config
Expand All @@ -20,3 +25,14 @@ func WithMaxConcurrentReconciles(max int) ControllerConfigOpts {
return nil
}
}

// WithRateLimiter sets the rate limiter for the controller
func WithRateLimiter(rateLimiter workqueue.RateLimiter) ControllerConfigOpts {
return func(c *ControllerConfig) error {
if rateLimiter == nil {
return errors.New("rate limiter cannot be nil")

Check warning on line 33 in controllers/options.go

View check run for this annotation

Codecov / codecov/patch

controllers/options.go#L31-L33

Added lines #L31 - L33 were not covered by tests
}
c.RateLimiter = rateLimiter
return nil

Check warning on line 36 in controllers/options.go

View check run for this annotation

Codecov / codecov/patch

controllers/options.go#L35-L36

Added lines #L35 - L36 were not covered by tests
}
}
17 changes: 15 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
_ "k8s.io/client-go/plugin/pkg/client/auth"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
capiv1 "sigs.k8s.io/cluster-api/api/v1beta1"
bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1"
capiflags "sigs.k8s.io/cluster-api/util/flags"
Expand Down Expand Up @@ -75,8 +76,13 @@ type managerConfig struct {
concurrentReconcilesNutanixMachine int
diagnosticsOptions capiflags.DiagnosticsOptions

logger logr.Logger
restConfig *rest.Config
logger logr.Logger
restConfig *rest.Config
rateLimiter workqueue.RateLimiter
}

func rateLimiter(baseDelay, maxDelay time.Duration) workqueue.RateLimiter {
return workqueue.NewItemExponentialFailureRateLimiter(baseDelay, maxDelay)
}

func parseFlags(config *managerConfig) {
Expand All @@ -88,6 +94,10 @@ func parseFlags(config *managerConfig) {
pflag.IntVar(&maxConcurrentReconciles, "max-concurrent-reconciles", defaultMaxConcurrentReconciles,
"The maximum number of allowed, concurrent reconciles.")

var baseDelay, maxDelay time.Duration
pflag.DurationVar(&baseDelay, "rate-limiter-base-delay", 500*time.Millisecond, "The base delay for the rate limiter.")
pflag.DurationVar(&maxDelay, "rate-limiter-max-delay", 15*time.Minute, "The maximum delay for the rate limiter.")

opts := zap.Options{
TimeEncoder: zapcore.RFC3339TimeEncoder,
}
Expand All @@ -100,6 +110,7 @@ func parseFlags(config *managerConfig) {

config.concurrentReconcilesNutanixCluster = maxConcurrentReconciles
config.concurrentReconcilesNutanixMachine = maxConcurrentReconciles
config.rateLimiter = rateLimiter(baseDelay, maxDelay)
}

func setupLogger() logr.Logger {
Expand Down Expand Up @@ -189,6 +200,7 @@ func runManager(ctx context.Context, mgr manager.Manager, config *managerConfig)

clusterControllerOpts := []controllers.ControllerConfigOpts{
controllers.WithMaxConcurrentReconciles(config.concurrentReconcilesNutanixCluster),
controllers.WithRateLimiter(config.rateLimiter),
}

if err := setupNutanixClusterController(ctx, mgr, secretInformer, configMapInformer, clusterControllerOpts...); err != nil {
Expand All @@ -197,6 +209,7 @@ func runManager(ctx context.Context, mgr manager.Manager, config *managerConfig)

machineControllerOpts := []controllers.ControllerConfigOpts{
controllers.WithMaxConcurrentReconciles(config.concurrentReconcilesNutanixMachine),
controllers.WithRateLimiter(config.rateLimiter),
}

if err := setupNutanixMachineController(ctx, mgr, secretInformer, configMapInformer, machineControllerOpts...); err != nil {
Expand Down
2 changes: 2 additions & 0 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"os"
"path/filepath"
"testing"
"time"

"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -125,6 +126,7 @@ func testRunManagerCommon(t *testing.T, ctrl *gomock.Controller) (*mockctlclient
concurrentReconcilesNutanixCluster: 1,
concurrentReconcilesNutanixMachine: 1,
restConfig: cfg,
rateLimiter: rateLimiter(500*time.Millisecond, 15*time.Minute),
}

client := mockctlclient.NewMockClient(ctrl)
Expand Down

0 comments on commit db0697d

Please sign in to comment.