【Temporal】Worker启动流程

代码入口: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对应的所有命令执行一遍。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Java Spring中初始化Temporal worker,您需要执行以下步骤: 1.添加Temporal Java SDK依赖项:您需要将以下依赖项添加到您的构建文件中(例如Maven或Gradle),以使用Temporal Java SDK: ``` <dependency> <groupId>io.temporal</groupId> <artifactId>temporal-sdk</artifactId> <version>1.0.0</version> </dependency> ``` 2.配置Temporal Worker:在您的Spring应用程序中,您需要创建一个新的Temporal Worker实例,并配置它以处理您的工作流或活动任务。您可以使用以下代码创建一个新的Temporal Worker实例: ``` TemporalWorker worker = TemporalWorker.newInstance(TemporalWorkerOptions.newBuilder() .setWorkflowHostPort("localhost:7233") .build()); ``` 在上面的代码中,您需要设置工作流主机和端口,以便Worker可以与Temporal Server进行通信。 3.注册工作流和活动:在创建Worker实例后,您需要注册您的工作流和活动任务,在Worker实例中处理它们。您可以使用以下代码进行注册: ``` worker.registerWorkflowImplementationTypes(MyWorkflowImpl.class); worker.registerActivitiesImplementations(new MyActivityImpl()); ``` 在上面的代码中,您需要将MyWorkflowImpl.class替换为您的工作流实现类,并将MyActivityImpl替换为您的活动实现类。 4.启动Worker:最后,您需要启动Worker实例,以便它可以开始处理工作流和活动任务。您可以使用以下代码启动Worker: ``` worker.run(); ``` 在上面的代码中,Worker将在当前线程中运行。如果您想要在后台线程中运行Worker,请使用以下代码: ``` worker.start(); ``` 这些是在Java Spring中初始化Temporal worker的基本步骤。您可以根据您的具体需求和应用程序架构进行调整和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值