@@ -64,6 +64,9 @@ type PoolWithFunc struct {
64
64
heartbeatDone int32
65
65
stopHeartbeat context.CancelFunc
66
66
67
+ ticktockDone int32
68
+ stopTicktock context.CancelFunc
69
+
67
70
now atomic.Value
68
71
69
72
options * Options
@@ -134,15 +137,44 @@ func (p *PoolWithFunc) purgeStaleWorkers(ctx context.Context) {
134
137
}
135
138
136
139
// ticktock is a goroutine that updates the current time in the pool regularly.
137
- func (p * PoolWithFunc ) ticktock () {
140
+ func (p * PoolWithFunc ) ticktock (ctx context. Context ) {
138
141
ticker := time .NewTicker (nowTimeUpdateInterval )
139
- defer ticker .Stop ()
142
+ defer func () {
143
+ ticker .Stop ()
144
+ atomic .StoreInt32 (& p .ticktockDone , 1 )
145
+ }()
146
+
147
+ for {
148
+ select {
149
+ case <- ctx .Done ():
150
+ return
151
+ case <- ticker .C :
152
+ }
153
+
154
+ if p .IsClosed () {
155
+ break
156
+ }
140
157
141
- for range ticker .C {
142
158
p .now .Store (time .Now ())
143
159
}
144
160
}
145
161
162
+ func (p * PoolWithFunc ) startHeartbeat () {
163
+ // Start a goroutine to clean up expired workers periodically.
164
+ var ctx context.Context
165
+ ctx , p .stopHeartbeat = context .WithCancel (context .Background ())
166
+ if ! p .options .DisablePurge {
167
+ go p .purgeStaleWorkers (ctx )
168
+ }
169
+ }
170
+
171
+ func (p * PoolWithFunc ) startTicktock () {
172
+ p .now .Store (time .Now ())
173
+ var ctx context.Context
174
+ ctx , p .stopTicktock = context .WithCancel (context .Background ())
175
+ go p .ticktock (ctx )
176
+ }
177
+
146
178
func (p * PoolWithFunc ) nowTime () time.Time {
147
179
return p .now .Load ().(time.Time )
148
180
}
@@ -191,15 +223,8 @@ func NewPoolWithFunc(size int, pf func(interface{}), options ...Option) (*PoolWi
191
223
}
192
224
p .cond = sync .NewCond (p .lock )
193
225
194
- // Start a goroutine to clean up expired workers periodically.
195
- var ctx context.Context
196
- ctx , p .stopHeartbeat = context .WithCancel (context .Background ())
197
- if ! p .options .DisablePurge {
198
- go p .purgeStaleWorkers (ctx )
199
- }
200
-
201
- p .now .Store (time .Now ())
202
- go p .ticktock ()
226
+ p .startHeartbeat ()
227
+ p .startTicktock ()
203
228
204
229
return p , nil
205
230
}
@@ -288,17 +313,21 @@ func (p *PoolWithFunc) Release() {
288
313
289
314
// ReleaseTimeout is like Release but with a timeout, it waits all workers to exit before timing out.
290
315
func (p * PoolWithFunc ) ReleaseTimeout (timeout time.Duration ) error {
291
- if p .IsClosed () || p .stopHeartbeat == nil {
316
+ if p .IsClosed () || p .stopHeartbeat == nil || p . stopTicktock == nil {
292
317
return ErrPoolClosed
293
318
}
294
319
295
320
p .stopHeartbeat ()
296
321
p .stopHeartbeat = nil
322
+ p .stopTicktock ()
323
+ p .stopTicktock = nil
297
324
p .Release ()
298
325
299
326
endTime := time .Now ().Add (timeout )
300
327
for time .Now ().Before (endTime ) {
301
- if p .Running () == 0 && (p .options .DisablePurge || atomic .LoadInt32 (& p .heartbeatDone ) == 1 ) {
328
+ if p .Running () == 0 &&
329
+ (p .options .DisablePurge || atomic .LoadInt32 (& p .heartbeatDone ) == 1 ) &&
330
+ atomic .LoadInt32 (& p .ticktockDone ) == 1 {
302
331
return nil
303
332
}
304
333
time .Sleep (10 * time .Millisecond )
@@ -310,11 +339,9 @@ func (p *PoolWithFunc) ReleaseTimeout(timeout time.Duration) error {
310
339
func (p * PoolWithFunc ) Reboot () {
311
340
if atomic .CompareAndSwapInt32 (& p .state , CLOSED , OPENED ) {
312
341
atomic .StoreInt32 (& p .heartbeatDone , 0 )
313
- var ctx context.Context
314
- ctx , p .stopHeartbeat = context .WithCancel (context .Background ())
315
- if ! p .options .DisablePurge {
316
- go p .purgeStaleWorkers (ctx )
317
- }
342
+ p .startHeartbeat ()
343
+ atomic .StoreInt32 (& p .ticktockDone , 0 )
344
+ p .startTicktock ()
318
345
}
319
346
}
320
347
0 commit comments