代码入口:temporal-go.sdk/internal/internal_worker.go
worker启动
// Start the worker in a non-blocking fashion.
func (aw *AggregatedWorker) Start() error {
aw.assertNotStopped()
if err := initBinaryChecksum(); err != nil {
return fmt.Errorf("failed to get executable checksum: %v", err)
} else if err = aw.client.ensureInitialized(); err != nil {
return err
}
// Populate the capabilities. This should be the only time it is written too.
capabilities, err := aw.client.loadCapabilities()
if err != nil {
return err
}
proto.Merge(aw.capabilities, capabilities)
if !util.IsInterfaceNil(aw.workflowWorker) {
if err := aw.workflowWorker.Start(); err != nil {
return err
}
}
if !util.IsInterfaceNil(aw.activityWorker) {
if err := aw.activityWorker.Start(); err != nil {
// stop workflow worker.
if !util.IsInterfaceNil(aw.workflowWorker) {
if aw.workflowWorker.worker.isWorkerStarted {
aw.workflowWorker.Stop()
}
}
return err
}
}
if !util.IsInterfaceNil(aw.sessionWorker) && len(aw.registry.getRegisteredActivities()) > 0 {
aw.logger.Info("Starting session worker")
if err := aw.sessionWorker.Start(); err != nil {
// stop workflow worker and activity worker.
if !util.IsInterfaceNil(aw.workflowWorker) {
if aw.workflowWorker.worker.isWorkerStarted {
aw.workflowWorker.Stop()
}
}
if !util.IsInterfaceNil(aw.activityWorker) {
if aw.activityWorker.worker.isWorkerStarted {
aw.activityWorker.Stop()
}
}
return err
}
}
aw.logger.Info("Started Worker")
return nil
}
上面就是根据不同的场景启动相应的worker
这里先看看workflow的启动:
// Start starts a fixed set of routines to do the work.
func (bw *baseWorker) Start() {
if bw.isWorkerStarted {
return
}
bw.metricsHandler.Counter(metrics.WorkerStartCounter).Inc(1)
for i := 0; i < bw.options.pollerCount; i++ {
bw.stopWG.Add(1)
go bw.runPoller()
}
bw.stopWG.Add(1)
go bw.runTaskDispatcher()
bw.isWorkerStarted = true
traceLog(func() {
bw.logger.Info("Started Worker",
"PollerCount", bw.options.pollerCount,
"MaxConcurrentTask", bw.options.maxConcurrentTask,
"MaxTaskPerSecond", bw.options.maxTaskPerSecond,
)
})
}
上面的逻辑如下:
1. 根据配置的任务拉取器数量,启动相应数量的任务拉取器
2. 启动任务分发器
任务拉取器
func (bw *baseWorker) runPoller() {
defer bw.stopWG.Done()
bw.metricsHandler.Counter(metrics.PollerStartCounter).Inc(1)
for {
select {
case <-bw.stopCh:
return
case <-bw.pollerRequestCh:
if bw.sessionTokenBucket != nil {
bw.sessionTokenBucket.waitForAvailableToken()
}
bw.pollTask()
}
}
}
func (bw *baseWorker) pollTask() {
var err error
var task interface{}
bw.retrier.Throttle(bw.stopCh)
if bw.pollLimiter == nil || bw.pollLimiter.Wait(bw.limiterContext) == nil {
task, err = bw.options.taskWorker.PollTask()
bw.logPollTaskError(err)
if err != nil {
// We retry "non retriable" errors while long polling for a while, because some proxies return
// unexpected values causing unnecessary downtime.
if isNonRetriableError(err) && bw.retrier.GetElapsedTime() > getRetryLongPollGracePeriod() {
bw.logger.Error("Worker received non-retriable error. Shutting down.", tagError, err)
if bw.fatalErrCb != nil {
bw.fatalErrCb(err)
}
return
}
// We use the secondary retrier on resource exhausted
_, resourceExhausted := err.(*serviceerror.ResourceExhausted)
bw.retrier.Failed(resourceExhausted)
} else {
bw.retrier.Succeeded()
}
}
if task != nil {
select {
case bw.taskQueueCh <- &polledTask{task}:
case <-bw.stopCh:
}
} else {
bw.pollerRequestCh <- struct{}{} // poll failed, trigger a new poll
}
}
上面的逻辑如下:
1. 启动一个loop轮训
2. 在循环中不断向temporal server发送请求,获取下一个任务
3. 将获取到的任务放入队列中
任务分发器
func (bw *baseWorker) runTaskDispatcher() {
defer bw.stopWG.Done()
for i := 0; i < bw.options.maxConcurrentTask; i++ {
bw.pollerRequestCh <- struct{}{}
}
for {
// wait for new task or worker stop
select {
case <-bw.stopCh:
return
case task := <-bw.taskQueueCh:
// for non-polled-task (local activity result as task), we don't need to rate limit
_, isPolledTask := task.(*polledTask)
if isPolledTask && bw.taskLimiter.Wait(bw.limiterContext) != nil {
if bw.isStop() {
return
}
}
bw.stopWG.Add(1)
go bw.processTask(task)
}
}
}
上面的逻辑如下:
1. 启动一个loop循环
2. 在循环中不断从任务队列中获取任务
3. 检查是否需要限流,如果需要则等待前面的任务完成
4. 处理任务
注:这里的任务是一个完整的workflow,就是我们执行executeWorkflow方法时向temporal server发送请求的时候,server创建的一个记录。后续我们在这个workflow上做的任何操作,都是作为这个任务对应的一系列命令,比如执行子workflow、创建activity等等。这里拉取一个task,就会把这个task对应的所有命令执行一遍。