@@ -66,6 +66,11 @@ const (
66
66
67
67
var nowFn = time .Now
68
68
69
+ type work struct {
70
+ id int
71
+ fn WorkFunc
72
+ }
73
+
69
74
type WriterLease struct {
70
75
name string
71
76
backoff wait.Backoff
@@ -74,7 +79,8 @@ type WriterLease struct {
74
79
once chan struct {}
75
80
76
81
lock sync.Mutex
77
- queued map [string ]WorkFunc
82
+ id int
83
+ queued map [string ]* work
78
84
queue workqueue.DelayingInterface
79
85
state State
80
86
expires time.Time
@@ -95,7 +101,7 @@ func New(leaseDuration, retryInterval time.Duration) *WriterLease {
95
101
maxBackoff : leaseDuration ,
96
102
retryInterval : retryInterval ,
97
103
98
- queued : make (map [string ]WorkFunc ),
104
+ queued : make (map [string ]* work ),
99
105
queue : workqueue .NewDelayingQueue (),
100
106
once : make (chan struct {}),
101
107
}
@@ -110,7 +116,7 @@ func NewWithBackoff(name string, leaseDuration, retryInterval time.Duration, bac
110
116
maxBackoff : leaseDuration ,
111
117
retryInterval : retryInterval ,
112
118
113
- queued : make (map [string ]WorkFunc ),
119
+ queued : make (map [string ]* work ),
114
120
queue : workqueue .NewNamedDelayingQueue (name ),
115
121
once : make (chan struct {}),
116
122
}
@@ -122,7 +128,8 @@ func (l *WriterLease) Run(stopCh <-chan struct{}) {
122
128
123
129
go func () {
124
130
defer utilruntime .HandleCrash ()
125
- l .work ()
131
+ for l .work () {
132
+ }
126
133
glog .V (4 ).Infof ("[%s] Worker stopped" , l .name )
127
134
}()
128
135
@@ -154,7 +161,8 @@ func (l *WriterLease) WaitUntil(t time.Duration) (bool, bool) {
154
161
func (l * WriterLease ) Try (key string , fn WorkFunc ) {
155
162
l .lock .Lock ()
156
163
defer l .lock .Unlock ()
157
- l .queued [key ] = fn
164
+ l .id ++
165
+ l .queued [key ] = & work {fn : fn , id : l .id }
158
166
if l .state == Follower {
159
167
delay := l .expires .Sub (nowFn ())
160
168
// no matter what, always wait at least some amount of time as a follower to give the nominal
@@ -195,7 +203,7 @@ func (l *WriterLease) Remove(key string) {
195
203
delete (l .queued , key )
196
204
}
197
205
198
- func (l * WriterLease ) get (key string ) WorkFunc {
206
+ func (l * WriterLease ) get (key string ) * work {
199
207
l .lock .Lock ()
200
208
defer l .lock .Unlock ()
201
209
return l .queued [key ]
@@ -207,49 +215,48 @@ func (l *WriterLease) leaseState() (State, time.Time, int) {
207
215
return l .state , l .expires , l .tick
208
216
}
209
217
210
- func (l * WriterLease ) work () {
211
- for {
212
- item , shutdown := l .queue .Get ()
213
- if shutdown {
214
- return
215
- }
216
- key := item .(string )
217
-
218
- fn := l .get (key )
219
- if fn == nil {
220
- glog .V (4 ).Infof ("[%s] Work item %s was cleared, done" , l .name , key )
221
- l .queue .Done (key )
222
- continue
223
- }
218
+ func (l * WriterLease ) work () bool {
219
+ item , shutdown := l .queue .Get ()
220
+ if shutdown {
221
+ return false
222
+ }
223
+ key := item .(string )
224
224
225
- leaseState , leaseExpires , _ := l .leaseState ()
226
- if leaseState == Follower {
227
- // if we are following, continue to defer work until the lease expires
228
- if remaining := leaseExpires .Sub (nowFn ()); remaining > 0 {
229
- glog .V (4 ).Infof ("[%s] Follower, %s remaining in lease" , l .name , remaining )
230
- l .queue .AddAfter (key , remaining )
231
- l .queue .Done (key )
232
- continue
233
- }
234
- glog .V (4 ).Infof ("[%s] Lease expired, running %s" , l .name , key )
235
- } else {
236
- glog .V (4 ).Infof ("[%s] Lease owner or electing, running %s" , l .name , key )
237
- }
225
+ work := l .get (key )
226
+ if work == nil {
227
+ glog .V (4 ).Infof ("[%s] Work item %s was cleared, done" , l .name , key )
228
+ l .queue .Done (key )
229
+ return true
230
+ }
238
231
239
- isLeader , retry := fn ()
240
- if retry {
241
- // come back in a bit
242
- glog .V (4 ).Infof ("[%s] Retrying %s" , l .name , key )
243
- l .queue .AddAfter (key , l .retryInterval )
232
+ leaseState , leaseExpires , _ := l .leaseState ()
233
+ if leaseState == Follower {
234
+ // if we are following, continue to defer work until the lease expires
235
+ if remaining := leaseExpires .Sub (nowFn ()); remaining > 0 {
236
+ glog .V (4 ).Infof ("[%s] Follower, %s remaining in lease" , l .name , remaining )
237
+ l .queue .AddAfter (key , remaining )
244
238
l .queue .Done (key )
245
- continue
239
+ return true
246
240
}
241
+ glog .V (4 ).Infof ("[%s] Lease expired, running %s" , l .name , key )
242
+ } else {
243
+ glog .V (4 ).Infof ("[%s] Lease owner or electing, running %s" , l .name , key )
244
+ }
247
245
248
- l .finishKey (key , isLeader )
246
+ isLeader , retry := work .fn ()
247
+ if retry {
248
+ // come back in a bit
249
+ glog .V (4 ).Infof ("[%s] Retrying %s" , l .name , key )
250
+ l .queue .AddAfter (key , l .retryInterval )
251
+ l .queue .Done (key )
252
+ return true
249
253
}
254
+
255
+ l .finishKey (key , isLeader , work .id )
256
+ return true
250
257
}
251
258
252
- func (l * WriterLease ) finishKey (key string , isLeader bool ) {
259
+ func (l * WriterLease ) finishKey (key string , isLeader bool , id int ) {
253
260
l .lock .Lock ()
254
261
defer l .lock .Unlock ()
255
262
@@ -271,7 +278,9 @@ func (l *WriterLease) finishKey(key string, isLeader bool) {
271
278
}
272
279
l .expires = nowFn ().Add (l .nextBackoff ())
273
280
}
274
- delete (l .queued , key )
281
+ if work , ok := l .queued [key ]; ok && work .id == id {
282
+ delete (l .queued , key )
283
+ }
275
284
// close the channel before we remove the key from the queue to prevent races in Wait
276
285
if resolvedElection {
277
286
close (l .once )
0 commit comments