Temporal 任务队列(Task Queue)和 Worker 进程(Worker Process)是紧密结合的组件。

任务(Task)是 Worker 推进特定的工作流执行(Workflow Execution)或 Activity 执行(Activity Execution)所需的上下文。

有两种类型的任务:


工作流任务

工作流任务(Workflow Task)是包含使工作流执行(Workflow Execution)取得进展所需的上下文的任务。


工作流任务执行

工作流任务执行(Workflow Task Execution)是指 Worker 获取到工作流任务,并使用它在工作流函数的执行上取得进展。


Activity 任务

Activity 任务(Activity Task)包含处理 Activity 任务执行(Activity Task Execution)所需的上下文。

Activity 任务主要表示 Activity Task Scheduled Event,它包含执行 Activity 函数(Activity Function)所需的数据。

如果正在传递心跳数据,那么 Activity 任务还将包含最新的心跳详情。


Activity 任务执行

Activity 任务执行(Activity Task Execution)是指 Worker 使用 Activity 任务(Activity Task)提供的上下文,执行 Activity 定义(Activity Definition)(也被称为 Activity 函数)。

ActivityTaskScheduled Event 对应于 Temporal 集群把 Activity 任务(Activity Task)放进任务队列(Task Queue)。

ActivityTaskStarted Event 对应于 Worker 从任务队列获取 Activity 任务。

ActivityTaskCompleted 或其它 Closed Activity Task Events 对应于 Worker 已经 yield 回 Temporal 集群。

调度 Activity 执行(Activity Execution)的 API 提供“事实上一次”("effectively once")体验,即便为成功地完成 Activity 可能发生多个 Activity 任务执行(Activity Task Executions)。

一旦 Activity 任务完成执行,Worker 会用一个特定的事件响应集群:


任务队列

任务队列(Task Queue)是轻量级的、动态分配的队列,一个或多个 Worker 实体(Worker Entities)从其中轮询任务(Tasks)。

任务队列没有任何顺序保证。如果 backlog 没被耗尽,那么任务可以在任务队列中停留一段时间。

有两种类型的任务队列,Activity 任务队列和 Workflow 任务队列。

task-queue.svg

任务队列是非常轻量级的组件。任务队列不需要显式注册,而是在工作流执行或 Activity 生成时或者在 Worker 进程订阅时按需创建。在创建任务队列时,以相同的名称同时创建 Workflow 任务队列和 Activity 任务队列。Temporal 应用程序可以使用的或 Temporal 集群能够维护的任务队列的数量没有限制。

Worker 通过同步的 RPC 轮询任务队列中的任务。该实现提供许多收益:

监听给定任务队列的所有 Worker 必须注册相同的 Activity 和/或 Workflow。一个特殊情况是在服务升级期间,在二进制发布时,注册暂时不对齐是可以的。

在哪里设置任务队列

开发者可以在四个地方设置任务队列的名称:

  1. 当生成工作流执行时,必须设置任务队列:

  2. 当创建 Worker 实体和运行 Worker 进程时,必须设置任务队列名称:

    注意监听相同任务队列名称的所有 Worker 实体必须被注册为处理相同的 Workflow 类型和 Activity 类型。

    如果 Worker 实体轮询到一个任务,但它不知道该任务的 Workflow 类型或 Activity 类型,它将使该任务失败。但是,任务的失败不会导致相关联的工作流执行失败。

  3. 当生成 Activity 执行时,可以提供任务队列名称:

    这是可选的。如果未提供,那么 Activity 执行从它的工作流执行继承任务队列名称。

  4. 当生成子工作流执行(Child Workflow Execution)时,可以提供任务队列名称:

    这是可选的。如果未提供,那么子工作流执行从它的父工作流执行(Parent Workflow Execution)继承任务队列名称。


粘性执行

粘性执行(Stiky Execution)是指 Worker 实体缓存工作流执行事件历史( Workflow Execution Event History),并创建专用的任务队列来监听。

粘性执行发生在 Worker 实体完成工作流执行的工作流任务链中的第一个工作流任务之后。

Worker 实体缓存工作流执行事件历史,开始轮询用于包含更新的工作流任务的专用任务队列,而非全部事件历史。

如果 Worker 实体没有在适当的时间内从专用任务队列中获取工作流任务,集群将在原始任务队列上重新开始调度工作流任务。另一个 Worker 实体可以重新启动工作流执行,可以给未来的工作流任务设置自己的粘性执行。

粘性执行是 Temporal 平台的默认行为。


任务路由

任务路由(Task Routing)是指任务队列与一个或多个 Worker 配对,主要用于 Activity 任务执行。

这也意味着可以使用多个任务队列,每个任务队列与一个 Worker 进程配对。

任务路由有许多适用的场景。

流控制

从任务队列中消费的 Worker 仅在有可用容量时才请求 Activity 任务,因此它不会因请求峰值而过载。如果创建 Activity 任务的速度快于 Worker 处理它们的速度,它们被积压在任务队列中。

限流

每个 Activity Worker 轮询和处理 Activity 任务的速率是可配置的。即使 Worker 有空闲容量,也不会超过该速率。也支持全局的任务队列速率限制。该限制在给定任务队列的所有 Worker 间生效。经常使用它限制 Activity 调用的下游服务的负载。

特定的环境

在某些场景下,你可能需要在专用环境里执行 Activity。为将 Activity 任务发送到该环境,可使用专用任务队列。

将 Activity 任务路由到特定主机

在某些使用场景下,比如文件处理或机器学习模型训练,Activity 任务必须被路由到特定的 Worker 进程或 Worker 实体。

比如,假设你有一个拥有如下三个独立的 Activity 的工作流:

第一个 Activity,下载文件,可能发生在任意主机上的任意 Worker 里。但第二和第三个 Activity 必须被与下载文件的第一个 Activity 相同的主机上的 Worker 执行。

在真实场景中,你可能在许多主机上扩展许多 Worker 进程。当需要时,你需要开发你的 Temporal 应用程序将任务路由到特定的 Worker 进程。

代码示例:

会话

一些 SDK 提供会话(Session)API,它提供一种直接的方式来确保 Activity 任务在相同的 Worker 上执行,而无需手动指定任务队列名称。会话也包含并发会话限制Worker 故障检测之类的特性。

将 Activity 任务路由到特定进程

一些 Activity 加载大规模数据集,并在进程中缓存它们。依赖这些数据集的 Activity 应该被路由到相同的进程。

在这种情况下,涉及的每个 Worker 进程存在唯一的任务队列。

具有不同处理能力的 Worker

有些 Worker 可能存在于 GPU 盒子和非 GPU 盒子上。在这种情况下,每种类型的盒子应该有它自己的任务队列,工作流可以选择其中一个来发送 Activity 任务。


多优先级

如果你的使用场景涉及多个优先级,你可以为每个优先级创建一个任务队列,并为每个优先级创建一个 Worker 池。


版本化

任务路由是对代码进行版本化的最简单方法。

如果你有一个新的向后不兼容的 Activity 定义,通过使用不同的任务队列来启动。