Skip to content
This repository was archived by the owner on Jul 5, 2025. It is now read-only.

Commit defab90

Browse files
authored
feat: introduce GenerateNextReconcileTimer interface and adjust default reconcile time function (#191)
* feat: introduce `GenerateNextReconcileTimer` interface and adjust default reconcile time function * chore: adjust implementation to take the value of the GenerateNextReconcileTime as a seed for randomness rather than a hardcoded valu * chore: rework implementation fo getNextReconcileTime
1 parent 2d8540b commit defab90

File tree

2 files changed

+48
-7
lines changed

2 files changed

+48
-7
lines changed

controller/lifecycle/spread.go

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package lifecycle
22

33
import (
44
"fmt"
5-
"math/rand"
5+
"math/rand/v2"
66
"time"
77

88
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -28,9 +28,20 @@ type RuntimeObjectSpreadReconcileStatus interface {
2828
SetNextReconcileTime(time v1.Time)
2929
}
3030

31-
// getNextReconcileTime returns a random time between 12 and 24 hours
32-
func getNextReconcileTime() time.Duration {
33-
return 12*time.Hour + time.Duration(rand.Int63n(12*60))*time.Minute
31+
type GenerateNextReconcileTimer interface {
32+
GenerateNextReconcileTime() time.Duration
33+
}
34+
35+
const defaultMaxReconcileDuration = 24 * time.Hour
36+
37+
// getNextReconcileTime returns a random time between [maxReconcileTime]/2 and [maxReconcileTime] hours
38+
func getNextReconcileTime(maxReconcileTime time.Duration) time.Duration {
39+
40+
minTime := maxReconcileTime.Minutes() / 2
41+
42+
jitter := rand.Int64N(int64(minTime))
43+
44+
return time.Duration(jitter+int64(minTime)) * time.Minute
3445
}
3546

3647
// onNextReconcile is a helper function to set the next reconcile time and return the requeueAfter time
@@ -42,7 +53,14 @@ func onNextReconcile(instanceStatusObj RuntimeObjectSpreadReconcileStatus, log *
4253

4354
// setNextReconcileTime calculates and sets the next reconcile time for the instance
4455
func setNextReconcileTime(instanceStatusObj RuntimeObjectSpreadReconcileStatus, log *logger.Logger) {
45-
nextReconcileTime := getNextReconcileTime()
56+
57+
var border = defaultMaxReconcileDuration
58+
if in, ok := instanceStatusObj.(GenerateNextReconcileTimer); ok {
59+
border = in.GenerateNextReconcileTime()
60+
}
61+
62+
nextReconcileTime := getNextReconcileTime(border)
63+
4664
log.Debug().Int64("minutes-till-next-execution", int64(nextReconcileTime.Minutes())).Msg("Setting next reconcile time for the instance")
4765
instanceStatusObj.SetNextReconcileTime(v1.NewTime(time.Now().Add(nextReconcileTime)))
4866
}

controller/lifecycle/spread_test.go

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"time"
66

77
"github.com/stretchr/testify/assert"
8+
"github.com/stretchr/testify/mock"
89
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
910

1011
"github.com/openmfp/golang-commons/controller/testSupport"
@@ -15,12 +16,12 @@ func TestGetNextReconcilationTime(t *testing.T) {
1516
expectedEarliest := 12 * time.Hour
1617
expectedLatest := 24 * time.Hour
1718

18-
actual := getNextReconcileTime()
19+
actual := getNextReconcileTime(defaultMaxReconcileDuration)
1920
if actual < expectedEarliest || actual > expectedLatest {
2021
t.Errorf("Expected time between %v and %v, but got %v", expectedEarliest, expectedLatest, actual)
2122
}
2223

23-
actual2 := getNextReconcileTime()
24+
actual2 := getNextReconcileTime(defaultMaxReconcileDuration)
2425
if actual2 < expectedEarliest || actual2 > expectedLatest {
2526
t.Errorf("Expected time between %v and %v, but got %v", expectedEarliest, expectedLatest, actual)
2627
}
@@ -52,6 +53,28 @@ func TestOnNextReconcile(t *testing.T) {
5253
assert.Contains(t, messages[0].Message, "no processing needed")
5354
}
5455

56+
type testInstance struct {
57+
mock.Mock
58+
*implementingSpreadReconciles
59+
}
60+
61+
func (t *testInstance) GenerateNextReconcileTime() time.Duration {
62+
args := t.Called()
63+
return args.Get(0).(time.Duration)
64+
}
65+
66+
func TestGenerateNextReconcileTimer(t *testing.T) {
67+
instance := &testInstance{
68+
implementingSpreadReconciles: &implementingSpreadReconciles{testSupport.TestApiObject{}},
69+
}
70+
71+
instance.On("GenerateNextReconcileTime").Return(10 * time.Minute)
72+
73+
setNextReconcileTime(instance, testlogger.New().Logger)
74+
75+
assert.True(t, instance.AssertCalled(t, "GenerateNextReconcileTime"))
76+
}
77+
5578
func TestUpdateObservedGeneration(t *testing.T) {
5679
instanceStatusObj := testSupport.TestStatus{
5780
ObservedGeneration: 0,

0 commit comments

Comments
 (0)