Skip to content

Commit 3b56aca

Browse files
committed
Add Priority field to reconcile.Result
Signed-off-by: Stefan Büringer [email protected]
1 parent 9190537 commit 3b56aca

File tree

3 files changed

+98
-5
lines changed

3 files changed

+98
-5
lines changed

pkg/internal/controller/controller.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,9 @@ func (c *Controller[request]) reconcileHandler(ctx context.Context, req request,
459459
// resource to be synced.
460460
log.V(5).Info("Reconciling")
461461
result, err := c.Reconcile(ctx, req)
462+
if result.Priority != nil {
463+
priority = *result.Priority
464+
}
462465
switch {
463466
case err != nil:
464467
if errors.Is(err, reconcile.TerminalError(nil)) {
@@ -468,9 +471,6 @@ func (c *Controller[request]) reconcileHandler(ctx context.Context, req request,
468471
}
469472
ctrlmetrics.ReconcileErrors.WithLabelValues(c.Name).Inc()
470473
ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelError).Inc()
471-
if !result.IsZero() {
472-
log.Info("Warning: Reconciler returned both a non-zero result and a non-nil error. The result will always be ignored if the error is non-nil and the non-nil error causes requeuing with exponential backoff. For more details, see: https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/reconcile#Reconciler")
473-
}
474474
log.Error(err, "Reconciler error")
475475
case result.RequeueAfter > 0:
476476
log.V(5).Info(fmt.Sprintf("Reconcile done, requeueing after %s", result.RequeueAfter))

pkg/internal/controller/controller_test.go

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -745,7 +745,36 @@ var _ = Describe("controller", func() {
745745
}}))
746746
})
747747

748-
It("should requeue a Request after a duration (but not rate-limitted) if the Result sets RequeueAfter (regardless of Requeue)", func(ctx SpecContext) {
748+
It("should use the priority from Result when the reconciler requests a requeue", func(ctx SpecContext) {
749+
q := &fakePriorityQueue{PriorityQueue: priorityqueue.New[reconcile.Request]("controller1")}
750+
ctrl.NewQueue = func(string, workqueue.TypedRateLimiter[reconcile.Request]) workqueue.TypedRateLimitingInterface[reconcile.Request] {
751+
return q
752+
}
753+
754+
go func() {
755+
defer GinkgoRecover()
756+
Expect(ctrl.Start(ctx)).NotTo(HaveOccurred())
757+
}()
758+
759+
q.PriorityQueue.AddWithOpts(priorityqueue.AddOpts{Priority: ptr.To(10)}, request)
760+
761+
By("Invoking Reconciler which will request a requeue")
762+
fakeReconcile.AddResult(reconcile.Result{Requeue: true, Priority: ptr.To(99)}, nil)
763+
Expect(<-reconciled).To(Equal(request))
764+
Eventually(func() []priorityQueueAddition {
765+
q.lock.Lock()
766+
defer q.lock.Unlock()
767+
return q.added
768+
}).Should(Equal([]priorityQueueAddition{{
769+
AddOpts: priorityqueue.AddOpts{
770+
RateLimited: true,
771+
Priority: ptr.To(99),
772+
},
773+
items: []reconcile.Request{request},
774+
}}))
775+
})
776+
777+
It("should requeue a Request after a duration (but not rate-limited) if the Result sets RequeueAfter (regardless of Requeue)", func(ctx SpecContext) {
749778
dq := &DelegatingQueue{TypedRateLimitingInterface: ctrl.NewQueue("controller1", nil)}
750779
ctrl.NewQueue = func(string, workqueue.TypedRateLimiter[reconcile.Request]) workqueue.TypedRateLimitingInterface[reconcile.Request] {
751780
return dq
@@ -775,7 +804,7 @@ var _ = Describe("controller", func() {
775804
Eventually(func() int { return dq.NumRequeues(request) }).Should(Equal(0))
776805
})
777806

778-
It("should retain the priority with RequeAfter", func(ctx SpecContext) {
807+
It("should retain the priority with RequeueAfter", func(ctx SpecContext) {
779808
q := &fakePriorityQueue{PriorityQueue: priorityqueue.New[reconcile.Request]("controller1")}
780809
ctrl.NewQueue = func(string, workqueue.TypedRateLimiter[reconcile.Request]) workqueue.TypedRateLimitingInterface[reconcile.Request] {
781810
return q
@@ -804,6 +833,35 @@ var _ = Describe("controller", func() {
804833
}}))
805834
})
806835

836+
It("should use the priority from Result with RequeueAfter", func(ctx SpecContext) {
837+
q := &fakePriorityQueue{PriorityQueue: priorityqueue.New[reconcile.Request]("controller1")}
838+
ctrl.NewQueue = func(string, workqueue.TypedRateLimiter[reconcile.Request]) workqueue.TypedRateLimitingInterface[reconcile.Request] {
839+
return q
840+
}
841+
842+
go func() {
843+
defer GinkgoRecover()
844+
Expect(ctrl.Start(ctx)).NotTo(HaveOccurred())
845+
}()
846+
847+
q.PriorityQueue.AddWithOpts(priorityqueue.AddOpts{Priority: ptr.To(10)}, request)
848+
849+
By("Invoking Reconciler which will ask for RequeueAfter")
850+
fakeReconcile.AddResult(reconcile.Result{RequeueAfter: time.Millisecond * 100, Priority: ptr.To(99)}, nil)
851+
Expect(<-reconciled).To(Equal(request))
852+
Eventually(func() []priorityQueueAddition {
853+
q.lock.Lock()
854+
defer q.lock.Unlock()
855+
return q.added
856+
}).Should(Equal([]priorityQueueAddition{{
857+
AddOpts: priorityqueue.AddOpts{
858+
After: time.Millisecond * 100,
859+
Priority: ptr.To(99),
860+
},
861+
items: []reconcile.Request{request},
862+
}}))
863+
})
864+
807865
It("should perform error behavior if error is not nil, regardless of RequeueAfter", func(ctx SpecContext) {
808866
dq := &DelegatingQueue{TypedRateLimitingInterface: ctrl.NewQueue("controller1", nil)}
809867
ctrl.NewQueue = func(string, workqueue.TypedRateLimiter[reconcile.Request]) workqueue.TypedRateLimitingInterface[reconcile.Request] {
@@ -862,6 +920,35 @@ var _ = Describe("controller", func() {
862920
}}))
863921
})
864922

923+
It("should use the priority from Result when there was an error", func(ctx SpecContext) {
924+
q := &fakePriorityQueue{PriorityQueue: priorityqueue.New[reconcile.Request]("controller1")}
925+
ctrl.NewQueue = func(string, workqueue.TypedRateLimiter[reconcile.Request]) workqueue.TypedRateLimitingInterface[reconcile.Request] {
926+
return q
927+
}
928+
929+
go func() {
930+
defer GinkgoRecover()
931+
Expect(ctrl.Start(ctx)).NotTo(HaveOccurred())
932+
}()
933+
934+
q.PriorityQueue.AddWithOpts(priorityqueue.AddOpts{Priority: ptr.To(10)}, request)
935+
936+
By("Invoking Reconciler which will return an error")
937+
fakeReconcile.AddResult(reconcile.Result{Priority: ptr.To(99)}, errors.New("oups, I did it again"))
938+
Expect(<-reconciled).To(Equal(request))
939+
Eventually(func() []priorityQueueAddition {
940+
q.lock.Lock()
941+
defer q.lock.Unlock()
942+
return q.added
943+
}).Should(Equal([]priorityQueueAddition{{
944+
AddOpts: priorityqueue.AddOpts{
945+
RateLimited: true,
946+
Priority: ptr.To(99),
947+
},
948+
items: []reconcile.Request{request},
949+
}}))
950+
})
951+
865952
PIt("should return if the queue is shutdown", func() {
866953
// TODO(community): write this test
867954
})

pkg/reconcile/reconcile.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ type Result struct {
4444
// RequeueAfter if greater than 0, tells the Controller to requeue the reconcile key after the Duration.
4545
// Implies that Requeue is true, there is no need to set Requeue to true at the same time as RequeueAfter.
4646
RequeueAfter time.Duration
47+
48+
// Priority is the priority with which the item gets enqueued, if Reconcile returns a non-terminal error,
49+
// or RequeueAfter or Requeue are set.
50+
// If Priority is not set the original Priority of the request is preserved.
51+
// Note: Priority is only respected if the controller is using a priorityqueue.PriorityQueue.
52+
Priority *int
4753
}
4854

4955
// IsZero returns true if this result is empty.

0 commit comments

Comments
 (0)