@@ -24,6 +24,7 @@ import (
2424 "k8s.io/client-go/tools/cache"
2525 "k8s.io/client-go/util/workqueue"
2626 "k8s.io/klog/v2"
27+ "sigs.k8s.io/controller-runtime/pkg/controller/priorityqueue"
2728
2829 "github.com/karmada-io/karmada/pkg/sharedcli/ratelimiterflag"
2930)
@@ -46,6 +47,35 @@ type AsyncWorker interface {
4647 Run (ctx context.Context , workerNumber int )
4748}
4849
50+ // LowPriority is the priority value for low priority items.
51+ const LowPriority = - 100
52+
53+ // AsyncPriorityWorker is an extension of AsyncWorker with priority queue support.
54+ type AsyncPriorityWorker interface {
55+ // EnqueueWithOpts generates the key of 'obj' according to a 'KeyFunc' then adds the key as an item to priority queue by 'AddWithOpts'.
56+ EnqueueWithOpts (opts AddOpts , obj any )
57+
58+ // AddWithOpts adds items to the priority queue with options.
59+ AddWithOpts (opts AddOpts , item ... any )
60+
61+ AsyncWorker
62+ }
63+
64+ // AddOpts defines the options for adding items to priority queue.
65+ type AddOpts struct {
66+ After time.Duration
67+ RateLimited bool
68+ Priority int
69+ }
70+
71+ func (o * AddOpts ) toPriorityQueueAddOpts () priorityqueue.AddOpts {
72+ return priorityqueue.AddOpts {
73+ After : o .After ,
74+ RateLimited : o .RateLimited ,
75+ Priority : o .Priority ,
76+ }
77+ }
78+
4979// QueueKey is the item key that stores in queue.
5080// The key could be arbitrary types.
5181//
@@ -61,6 +91,7 @@ type KeyFunc func(obj interface{}) (QueueKey, error)
6191type ReconcileFunc func (key QueueKey ) error
6292
6393type asyncWorker struct {
94+ name string
6495 // keyFunc is the function that make keys for API objects.
6596 keyFunc KeyFunc
6697 // reconcileFunc is the function that process keys from the queue.
@@ -77,16 +108,28 @@ type Options struct {
77108 KeyFunc KeyFunc
78109 ReconcileFunc ReconcileFunc
79110 RateLimiterOptions ratelimiterflag.Options
111+ UsePriorityQueue bool
80112}
81113
82114// NewAsyncWorker returns a asyncWorker which can process resource periodic.
83- func NewAsyncWorker (opt Options ) AsyncWorker {
115+ func NewAsyncWorker (opt Options ) AsyncPriorityWorker {
116+ var queue workqueue.TypedRateLimitingInterface [any ]
117+ if opt .UsePriorityQueue {
118+ rateLimiterOpts := opt .RateLimiterOptions .SetDefaults ()
119+ queue = priorityqueue .New [any ](opt .Name , func (o * priorityqueue.Opts [any ]) {
120+ // change to controller-runtime priorityqueue default rateLimiter
121+ o .RateLimiter = workqueue .NewTypedItemExponentialFailureRateLimiter [any ](rateLimiterOpts .RateLimiterBaseDelay , rateLimiterOpts .RateLimiterMaxDelay )
122+ })
123+ } else {
124+ queue = workqueue .NewTypedRateLimitingQueueWithConfig (ratelimiterflag.DefaultControllerRateLimiter [any ](opt .RateLimiterOptions ), workqueue.TypedRateLimitingQueueConfig [any ]{
125+ Name : opt .Name ,
126+ })
127+ }
84128 return & asyncWorker {
129+ name : opt .Name ,
85130 keyFunc : opt .KeyFunc ,
86131 reconcileFunc : opt .ReconcileFunc ,
87- queue : workqueue .NewTypedRateLimitingQueueWithConfig (ratelimiterflag.DefaultControllerRateLimiter [any ](opt .RateLimiterOptions ), workqueue.TypedRateLimitingQueueConfig [any ]{
88- Name : opt .Name ,
89- }),
132+ queue : queue ,
90133 }
91134}
92135
@@ -104,6 +147,20 @@ func (w *asyncWorker) Enqueue(obj interface{}) {
104147 w .Add (key )
105148}
106149
150+ func (w * asyncWorker ) EnqueueWithOpts (opts AddOpts , obj any ) {
151+ key , err := w .keyFunc (obj )
152+ if err != nil {
153+ klog .Errorf ("Failed to generate key for obj: %+v, err: %v" , obj , err )
154+ return
155+ }
156+
157+ if key == nil {
158+ return
159+ }
160+
161+ w .AddWithOpts (opts , key )
162+ }
163+
107164func (w * asyncWorker ) Add (item interface {}) {
108165 if item == nil {
109166 klog .Warningf ("Ignore nil item from queue" )
@@ -122,6 +179,24 @@ func (w *asyncWorker) AddAfter(item interface{}, duration time.Duration) {
122179 w .queue .AddAfter (item , duration )
123180}
124181
182+ func (w * asyncWorker ) AddWithOpts (opts AddOpts , item ... any ) {
183+ if item == nil {
184+ klog .Warningf ("Ignore nil item from queue" )
185+ return
186+ }
187+
188+ pq , ok := w .queue .(priorityqueue.PriorityQueue [any ])
189+ if ! ok {
190+ klog .Warningf ("queue is not priority queue, fallback to normal queue, queueName: %s" , w .name )
191+ for _ , it := range item {
192+ w .queue .Add (it )
193+ }
194+ return
195+ }
196+
197+ pq .AddWithOpts (opts .toPriorityQueueAddOpts (), item ... )
198+ }
199+
125200func (w * asyncWorker ) worker () {
126201 key , quit := w .queue .Get ()
127202 if quit {
0 commit comments