Skip to content

Commit 8db6d98

Browse files
committed
feat: added validation and rw mutex
On-behalf-of: SAP [email protected]
1 parent 7ccebe3 commit 8db6d98

File tree

5 files changed

+44
-12
lines changed

5 files changed

+44
-12
lines changed

controller/lifecycle/controllerruntime/lifecycle.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,15 @@ func (l *LifecycleManager) SetupWithManagerBuilder(mgr ctrl.Manager, maxReconcil
8484
return nil, fmt.Errorf("cannot use conditions or spread reconciles in read-only mode")
8585
}
8686

87+
rateLimiter, err := ratelimiter.NewStaticThenExponentialRateLimiter[reconcile.Request](l.rateLimiterConfig)
88+
if err != nil {
89+
return nil, err
90+
}
91+
8792
eventPredicates = append([]predicate.Predicate{filter.DebugResourcesBehaviourPredicate(debugLabelValue)}, eventPredicates...)
8893
opts := controller.Options{
8994
MaxConcurrentReconciles: maxReconciles,
90-
RateLimiter: ratelimiter.NewStaticThenExponentialRateLimiter[reconcile.Request](l.rateLimiterConfig),
95+
RateLimiter: rateLimiter,
9196
}
9297

9398
return ctrl.NewControllerManagedBy(mgr).

controller/lifecycle/multicluster/lifecycle.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,15 @@ func (l *LifecycleManager) SetupWithManagerBuilder(mgr mcmanager.Manager, maxRec
9494
return nil, fmt.Errorf("cannot use conditions or spread reconciles in read-only mode")
9595
}
9696

97+
rateLimiter, err := ratelimiter.NewStaticThenExponentialRateLimiter[mcreconcile.Request](l.rateLimiterConfig)
98+
if err != nil{
99+
return nil, err
100+
}
101+
97102
eventPredicates = append([]predicate.Predicate{filter.DebugResourcesBehaviourPredicate(debugLabelValue)}, eventPredicates...)
98103
opts := controller.TypedOptions[mcreconcile.Request]{
99104
MaxConcurrentReconciles: maxReconciles,
100-
RateLimiter: ratelimiter.NewStaticThenExponentialRateLimiter[mcreconcile.Request](l.rateLimiterConfig),
105+
RateLimiter: rateLimiter,
101106
}
102107

103108
return mcbuilder.ControllerManagedBy(mgr).

controller/lifecycle/ratelimiter/config.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package ratelimiter
22

33
import (
4+
"fmt"
45
"time"
56
)
67

@@ -18,6 +19,22 @@ var defaultConfig = Config{
1819
ExponentialMaxBackoff: 2 * time.Minute,
1920
}
2021

22+
func (c Config) validate() error {
23+
if c.StaticRequeueDelay < 0 {
24+
return fmt.Errorf("the static requeue delay shouldn't be negative")
25+
}
26+
if c.ExponentialInitialBackoff < 0 {
27+
return fmt.Errorf("the initial exponential backoff shouldn't be negative")
28+
}
29+
if c.StaticRequeueDelay > c.ExponentialInitialBackoff {
30+
return fmt.Errorf("the initial exponential backoff should be equal to or greater than the static requeue delay")
31+
}
32+
if c.StaticWindow < c.StaticRequeueDelay {
33+
return fmt.Errorf("the static window duration should be equal to or greater than the static requeue delay")
34+
}
35+
return nil
36+
}
37+
2138
type Option func(*Config)
2239

2340
func WithStaticWindow(d time.Duration) Option {
@@ -52,4 +69,4 @@ func NewConfig(options ...Option) Config {
5269
}
5370

5471
return cfg
55-
}
72+
}

controller/lifecycle/ratelimiter/static_exponential.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
)
1010

1111
type StaticThenExponentialRateLimiter[T comparable] struct {
12-
failuresLock sync.Mutex
12+
failuresLock sync.RWMutex
1313
firstAttempt map[T]time.Time
1414

1515
staticDelay time.Duration
@@ -19,7 +19,10 @@ type StaticThenExponentialRateLimiter[T comparable] struct {
1919
clock clock.Clock
2020
}
2121

22-
func NewStaticThenExponentialRateLimiter[T comparable](cfg Config) *StaticThenExponentialRateLimiter[T] {
22+
func NewStaticThenExponentialRateLimiter[T comparable](cfg Config) (*StaticThenExponentialRateLimiter[T], error) {
23+
if err := cfg.validate(); err != nil {
24+
return nil, err
25+
}
2326
return &StaticThenExponentialRateLimiter[T]{
2427
staticDelay: cfg.StaticRequeueDelay,
2528
staticWindow: cfg.StaticWindow,
@@ -29,19 +32,20 @@ func NewStaticThenExponentialRateLimiter[T comparable](cfg Config) *StaticThenEx
2932
),
3033
firstAttempt: make(map[T]time.Time),
3134
clock: clock.RealClock{},
32-
}
35+
},nil
3336
}
3437

3538
func (r *StaticThenExponentialRateLimiter[T]) When(item T) time.Duration {
36-
r.failuresLock.Lock()
37-
defer r.failuresLock.Unlock()
38-
3939
now := r.clock.Now()
4040

41+
r.failuresLock.RLock()
4142
first, exists := r.firstAttempt[item]
43+
r.failuresLock.RUnlock()
4244
if !exists {
43-
first = now
44-
r.firstAttempt[item] = first
45+
r.failuresLock.Lock()
46+
r.firstAttempt[item] = now
47+
r.failuresLock.Unlock()
48+
return r.staticDelay
4549
}
4650

4751
timeSinceFirst := now.Sub(first)

controller/lifecycle/ratelimiter/static_exponential_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ func TestStaticThenExponentialRateLimiter_Forget(t *testing.T) {
1717
ExponentialInitialBackoff: 2 * time.Second,
1818
ExponentialMaxBackoff: 1 * time.Minute,
1919
}
20-
limiter := NewStaticThenExponentialRateLimiter[reconcile.Request](cfg)
20+
limiter, err := NewStaticThenExponentialRateLimiter[reconcile.Request](cfg)
21+
require.Nil(t, err)
2122
fakeClock := clocktesting.NewFakeClock(time.Now())
2223
limiter.clock = fakeClock
2324

0 commit comments

Comments
 (0)