@@ -33,6 +33,7 @@ import (
33
33
"time"
34
34
35
35
"go.uber.org/cadence/internal/common/debug"
36
+ "go.uber.org/cadence/internal/worker"
36
37
37
38
"github.com/uber-go/tally"
38
39
"go.uber.org/zap"
@@ -141,7 +142,7 @@ type (
141
142
logger * zap.Logger
142
143
metricsScope tally.Scope
143
144
144
- pollerRequestCh chan struct {}
145
+ concurrency * worker. ConcurrencyLimit
145
146
pollerAutoScaler * pollerAutoScaler
146
147
taskQueueCh chan interface {}
147
148
sessionTokenBucket * sessionTokenBucket
@@ -167,11 +168,17 @@ func createPollRetryPolicy() backoff.RetryPolicy {
167
168
func newBaseWorker (options baseWorkerOptions , logger * zap.Logger , metricsScope tally.Scope , sessionTokenBucket * sessionTokenBucket ) * baseWorker {
168
169
ctx , cancel := context .WithCancel (context .Background ())
169
170
171
+ concurrency := & worker.ConcurrencyLimit {
172
+ PollerPermit : worker .NewResizablePermit (options .pollerCount ),
173
+ TaskPermit : worker .NewResizablePermit (options .maxConcurrentTask ),
174
+ }
175
+
170
176
var pollerAS * pollerAutoScaler
171
177
if pollerOptions := options .pollerAutoScaler ; pollerOptions .Enabled {
172
178
pollerAS = newPollerScaler (
173
179
pollerOptions ,
174
180
logger ,
181
+ concurrency .PollerPermit ,
175
182
)
176
183
}
177
184
@@ -182,7 +189,7 @@ func newBaseWorker(options baseWorkerOptions, logger *zap.Logger, metricsScope t
182
189
retrier : backoff .NewConcurrentRetrier (pollOperationRetryPolicy ),
183
190
logger : logger .With (zapcore.Field {Key : tagWorkerType , Type : zapcore .StringType , String : options .workerType }),
184
191
metricsScope : tagScope (metricsScope , tagWorkerType , options .workerType ),
185
- pollerRequestCh : make ( chan struct {}, options . maxConcurrentTask ) ,
192
+ concurrency : concurrency ,
186
193
pollerAutoScaler : pollerAS ,
187
194
taskQueueCh : make (chan interface {}), // no buffer, so poller only able to poll new task after previous is dispatched.
188
195
limiterContext : ctx ,
@@ -241,14 +248,19 @@ func (bw *baseWorker) runPoller() {
241
248
bw .metricsScope .Counter (metrics .PollerStartCounter ).Inc (1 )
242
249
243
250
for {
251
+ permitChannel , channelDone := bw .concurrency .TaskPermit .AcquireChan (bw .limiterContext )
244
252
select {
245
253
case <- bw .shutdownCh :
254
+ channelDone ()
246
255
return
247
- case <- bw .pollerRequestCh :
248
- bw .metricsScope .Gauge (metrics .ConcurrentTaskQuota ).Update (float64 (cap (bw .pollerRequestCh )))
249
- // This metric is used to monitor how many poll requests have been allocated
250
- // and can be used to approximate number of concurrent task running (not pinpoint accurate)
251
- bw .metricsScope .Gauge (metrics .PollerRequestBufferUsage ).Update (float64 (cap (bw .pollerRequestCh ) - len (bw .pollerRequestCh )))
256
+ case <- permitChannel : // don't poll unless there is a task permit
257
+ channelDone ()
258
+ // TODO move to a centralized place inside the worker
259
+ // emit metrics on concurrent task permit quota and current task permit count
260
+ // NOTE task permit doesn't mean there is a task running, it still needs to poll until it gets a task to process
261
+ // thus the metrics is only an estimated value of how many tasks are running concurrently
262
+ bw .metricsScope .Gauge (metrics .ConcurrentTaskQuota ).Update (float64 (bw .concurrency .TaskPermit .Quota ()))
263
+ bw .metricsScope .Gauge (metrics .PollerRequestBufferUsage ).Update (float64 (bw .concurrency .TaskPermit .Count ()))
252
264
if bw .sessionTokenBucket != nil {
253
265
bw .sessionTokenBucket .waitForAvailableToken ()
254
266
}
@@ -260,10 +272,6 @@ func (bw *baseWorker) runPoller() {
260
272
func (bw * baseWorker ) runTaskDispatcher () {
261
273
defer bw .shutdownWG .Done ()
262
274
263
- for i := 0 ; i < bw .options .maxConcurrentTask ; i ++ {
264
- bw .pollerRequestCh <- struct {}{}
265
- }
266
-
267
275
for {
268
276
// wait for new task or shutdown
269
277
select {
@@ -294,10 +302,10 @@ func (bw *baseWorker) pollTask() {
294
302
var task interface {}
295
303
296
304
if bw .pollerAutoScaler != nil {
297
- if pErr := bw .pollerAutoScaler . Acquire (1 ); pErr == nil {
298
- defer bw .pollerAutoScaler . Release (1 )
305
+ if pErr := bw .concurrency . PollerPermit . Acquire (bw . limiterContext ); pErr == nil {
306
+ defer bw .concurrency . PollerPermit . Release ()
299
307
} else {
300
- bw .logger .Warn ("poller auto scaler acquire error" , zap .Error (pErr ))
308
+ bw .logger .Warn ("poller permit acquire error" , zap .Error (pErr ))
301
309
}
302
310
}
303
311
@@ -333,7 +341,7 @@ func (bw *baseWorker) pollTask() {
333
341
case <- bw .shutdownCh :
334
342
}
335
343
} else {
336
- bw .pollerRequestCh <- struct {}{} // poll failed, trigger a new poll
344
+ bw .concurrency . TaskPermit . Release () // poll failed, trigger a new poll by returning a task permit
337
345
}
338
346
}
339
347
@@ -368,7 +376,7 @@ func (bw *baseWorker) processTask(task interface{}) {
368
376
}
369
377
370
378
if isPolledTask {
371
- bw .pollerRequestCh <- struct {}{}
379
+ bw .concurrency . TaskPermit . Release () // task processed, trigger a new poll by returning a task permit
372
380
}
373
381
}()
374
382
err := bw .options .taskWorker .ProcessTask (task )
0 commit comments