@@ -18,6 +18,7 @@ import (
18
18
"context"
19
19
"errors"
20
20
"fmt"
21
+ "sync"
21
22
"time"
22
23
23
24
"github.com/samber/lo"
@@ -74,7 +75,9 @@ func NewQueueKey(pod *v1.Pod) QueueKey {
74
75
75
76
type Queue struct {
76
77
workqueue.RateLimitingInterface
77
- sets.Set [QueueKey ]
78
+
79
+ mu sync.Mutex
80
+ set sets.Set [QueueKey ]
78
81
79
82
kubeClient client.Client
80
83
recorder events.Recorder
@@ -83,7 +86,7 @@ type Queue struct {
83
86
func NewQueue (kubeClient client.Client , recorder events.Recorder ) * Queue {
84
87
queue := & Queue {
85
88
RateLimitingInterface : workqueue .NewRateLimitingQueue (workqueue .NewItemExponentialFailureRateLimiter (evictionQueueBaseDelay , evictionQueueMaxDelay )),
86
- Set : sets .New [QueueKey ](),
89
+ set : sets .New [QueueKey ](),
87
90
kubeClient : kubeClient ,
88
91
recorder : recorder ,
89
92
}
@@ -100,15 +103,25 @@ func (q *Queue) Builder(_ context.Context, m manager.Manager) controller.Builder
100
103
101
104
// Add adds pods to the Queue
102
105
func (q * Queue ) Add (pods ... * v1.Pod ) {
106
+ q .mu .Lock ()
107
+ defer q .mu .Unlock ()
108
+
103
109
for _ , pod := range pods {
104
110
qk := NewQueueKey (pod )
105
- if ! q .Set .Has (qk ) {
106
- q .Set .Insert (qk )
111
+ if ! q .set .Has (qk ) {
112
+ q .set .Insert (qk )
107
113
q .RateLimitingInterface .Add (qk )
108
114
}
109
115
}
110
116
}
111
117
118
+ func (q * Queue ) Has (pod * v1.Pod ) bool {
119
+ q .mu .Lock ()
120
+ defer q .mu .Unlock ()
121
+
122
+ return q .set .Has (NewQueueKey (pod ))
123
+ }
124
+
112
125
func (q * Queue ) Reconcile (ctx context.Context , _ reconcile.Request ) (reconcile.Result , error ) {
113
126
// Check if the queue is empty. client-go recommends not using this function to gate the subsequent
114
127
// get call, but since we're popping items off the queue synchronously, there should be no synchonization
@@ -126,7 +139,9 @@ func (q *Queue) Reconcile(ctx context.Context, _ reconcile.Request) (reconcile.R
126
139
// Evict pod
127
140
if q .Evict (ctx , qk ) {
128
141
q .RateLimitingInterface .Forget (qk )
129
- q .Set .Delete (qk )
142
+ q .mu .Lock ()
143
+ q .set .Delete (qk )
144
+ q .mu .Unlock ()
130
145
return reconcile.Result {RequeueAfter : controller .Immediately }, nil
131
146
}
132
147
// Requeue pod if eviction failed
@@ -170,6 +185,9 @@ func (q *Queue) Evict(ctx context.Context, key QueueKey) bool {
170
185
}
171
186
172
187
func (q * Queue ) Reset () {
188
+ q .mu .Lock ()
189
+ defer q .mu .Unlock ()
190
+
173
191
q .RateLimitingInterface = workqueue .NewRateLimitingQueue (workqueue .NewItemExponentialFailureRateLimiter (evictionQueueBaseDelay , evictionQueueMaxDelay ))
174
- q .Set = sets .New [QueueKey ]()
192
+ q .set = sets .New [QueueKey ]()
175
193
}
0 commit comments