Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/libs/smartrequeue.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ Use `NewStore` in the constructor of the reconciler. During reconciliation, the
- `Never` does not requeue the object
- `Backoff` requeues the object with an increasing backoff every time it is called on the same object
- `Reset` requeues the object, but resets the duration to its minimal value

There is also an integration into the [status updater](./status.md) for the smart requeuing logic.
7 changes: 7 additions & 0 deletions docs/libs/status.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,3 +181,10 @@ The `ReconcileResult` that is passed into the status updater is expected to cont
- If this is nil, `Object` will be used instead.
- If this is non-nil, it must not point to the same instance as `Object` - use the `DeepCopy()` function to create a different instance.
- All changes to `Object`'s status that are not part to `OldObject`'s status will be included in the patch during the status update. This can be used to inject custom changes to the status into the status update (in addition to the `WithCustomUpdateFunc` mentioned above).
- `SmartRequeue` contains the requeuing information for the [smart requeuing logic](./smartrequeue.md).
- This field has no effect unless `WithSmartRequeue` has been called on the status updater builder.
- If `ReconcileError` is not nil, the value has no effect and the smart requeue error logic is used instead.
- Valid values are:
- `Backoff` to requeue the object with an increasing backoff
- `Reset` to requeue the object, but reset the backoff interval to its minimum
- `NoRequeue` to not requeue the object
9 changes: 5 additions & 4 deletions pkg/controller/status_updater.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,8 @@ const (
// If the 'Result' field in the ReconcileResult has a non-zero RequeueAfter value set, that one is used if it is earlier than the one from smart requeue or if "NoRequeue" has been specified.
// This function only has an effect if the Object in the ReconcileResult is not nil, the smart requeue store is not nil, and the action is one of the known values.
// Also, if a reconciliation error occurred, the requeue interval will be reset, but no requeueAfter duration will be set, because controller-runtime will take care of requeuing the object anyway.
func (b *StatusUpdaterBuilder[Obj]) WithSmartRequeue(store *smartrequeue.Store, action SmartRequeueAction) *StatusUpdaterBuilder[Obj] {
func (b *StatusUpdaterBuilder[Obj]) WithSmartRequeue(store *smartrequeue.Store) *StatusUpdaterBuilder[Obj] {
b.internal.smartRequeueStore = store
b.internal.smartRequeueAction = action
return b
}

Expand Down Expand Up @@ -183,7 +182,6 @@ type statusUpdater[Obj client.Object] struct {
eventRecorder record.EventRecorder
eventVerbosity conditions.EventVerbosity
smartRequeueStore *smartrequeue.Store
smartRequeueAction SmartRequeueAction
}

func newStatusUpdater[Obj client.Object]() *statusUpdater[Obj] {
Expand Down Expand Up @@ -297,7 +295,7 @@ func (s *statusUpdater[Obj]) UpdateStatus(ctx context.Context, c client.Client,
if rr.ReconcileError != nil {
srRes, _ = s.smartRequeueStore.For(rr.Object).Error(rr.ReconcileError)
} else {
switch s.smartRequeueAction {
switch rr.SmartRequeue {
case SR_BACKOFF:
srRes, _ = s.smartRequeueStore.For(rr.Object).Backoff()
case SR_RESET:
Expand Down Expand Up @@ -424,6 +422,9 @@ type ReconcileResult[Obj client.Object] struct {
// ConditionsToRemove is an optional slice of condition types for which the corresponding conditions should be removed from the status.
// This is useful if you want to remove conditions that are no longer relevant.
ConditionsToRemove []string
// SmartRequeue determines if/when the object should be requeued.
// Has no effect unless WithSmartRequeue() has been called on the status updater.
SmartRequeue SmartRequeueAction
}

// GenerateCreateConditionFunc returns a function that can be used to add a condition to the given ReconcileResult.
Expand Down
12 changes: 7 additions & 5 deletions pkg/controller/status_updater_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,13 +196,14 @@ var _ = Describe("Status Updater", func() {
obj := &CustomObject{}
Expect(env.Client().Get(env.Ctx, controller.ObjectKey("status", "default"), obj)).To(Succeed())
rr := controller.ReconcileResult[*CustomObject]{
Object: obj,
Conditions: dummyConditions(),
Object: obj,
Conditions: dummyConditions(),
SmartRequeue: controller.SR_RESET,
}
store := smartrequeue.NewStore(1*time.Second, 10*time.Second, 2.0)
su := preconfiguredStatusUpdaterBuilder().WithPhaseUpdateFunc(func(obj *CustomObject, rr controller.ReconcileResult[*CustomObject]) (string, error) {
return PhaseSucceeded, nil
}).WithSmartRequeue(store, controller.SR_RESET).Build()
}).WithSmartRequeue(store).Build()
res, err := su.UpdateStatus(env.Ctx, env.Client(), rr)
Expect(err).ToNot(HaveOccurred())
Expect(res.RequeueAfter).To(Equal(1 * time.Second))
Expand All @@ -218,11 +219,12 @@ var _ = Describe("Status Updater", func() {
Result: ctrl.Result{
RequeueAfter: 30 * time.Second,
},
SmartRequeue: controller.SR_RESET,
}
store := smartrequeue.NewStore(1*time.Second, 10*time.Second, 2.0)
su := preconfiguredStatusUpdaterBuilder().WithPhaseUpdateFunc(func(obj *CustomObject, rr controller.ReconcileResult[*CustomObject]) (string, error) {
return PhaseSucceeded, nil
}).WithSmartRequeue(store, controller.SR_RESET).Build()
}).WithSmartRequeue(store).Build()
res, err := su.UpdateStatus(env.Ctx, env.Client(), rr)
Expect(err).ToNot(HaveOccurred())
Expect(res.RequeueAfter).To(Equal(1 * time.Second))
Expand All @@ -231,7 +233,7 @@ var _ = Describe("Status Updater", func() {
store = smartrequeue.NewStore(1*time.Minute, 10*time.Minute, 2.0)
su = preconfiguredStatusUpdaterBuilder().WithPhaseUpdateFunc(func(obj *CustomObject, rr controller.ReconcileResult[*CustomObject]) (string, error) {
return PhaseSucceeded, nil
}).WithSmartRequeue(store, controller.SR_RESET).Build()
}).WithSmartRequeue(store).Build()
res, err = su.UpdateStatus(env.Ctx, env.Client(), rr)
Expect(err).ToNot(HaveOccurred())
Expect(res.RequeueAfter).To(Equal(30 * time.Second))
Expand Down