1. Temporal 基础概念:工作流、活动、任务队列与工作流执行

Temporal 是一个分布式、可扩展、持久化的工作流编排引擎。要理解其 DAG 边界与数据一致性保障,首先需要掌握四个最核心的抽象概念:工作流 (Workflow)、活动 (Activity)、任务队列 (Task Queue) 和 工作流执行 (Workflow Execution)。它们共同构成了 Temporal 应用的基本运行单元与通信模型。

1.1 核心概念定义

概念 英文 定义 类比(现实世界)
工作流 Workflow 一段可执行的代码逻辑,用于编排多个步骤(活动)的执行顺序、重试策略、超时设置以及补偿逻辑。工作流代码必须是确定性的(Deterministic)。 一份详细的商业合同或项目流程图,规定了“先做什么,后做什么”。
活动 Activity 工作流中一个具体的、有状态的业务操作单元。活动可以包含非确定性代码(如网络调用、数据库读写、文件操作)。 合同中的一条具体条款执行,例如“调用支付网关扣款”或“发送确认邮件”。
任务队列 Task Queue 一个逻辑上的缓冲通道,用于将工作流任务(Workflow Task)和活动任务(Activity Task)分发给对应的 Worker 进程。 公司内部的“任务分派箱”,不同部门(Worker)从对应的箱子里领取任务。
工作流执行 Workflow Execution 工作流代码的一次具体运行实例。每个执行实例都有唯一的标识符(Workflow ID + Run ID),并拥有独立的执行状态和历史记录。 一份合同从签署到履行完毕的完整生命周期。

1.2 概念关系与执行流程

这四个概念在 Temporal 系统中通过 Worker 和 Server 的协作紧密关联。下图展示了从工作流定义到一次完整执行的核心交互关系:

Temporal 核心概念关系图 Temporal 核心概念关系与执行流程 工作流 (Workflow) 编排逻辑 / 确定性代码 活动 (Activity) 业务操作 / 非确定性代码 任务队列 (Task Queue) 缓冲通道 / 任务分派 Temporal Server 事件存储 状态管理 任务调度 历史记录 Worker 执行工作流代码 执行活动代码 心跳上报 结果回传 轮询 / 分派 工作流执行 (Workflow Execution) Workflow ID + Run ID | 独立状态 | 事件历史 每个执行实例 对应唯一的事件历史

1.3 关键关系详解

核心原则:工作流负责“编排”,活动负责“执行”。工作流代码必须是确定性的,以确保在任何 Worker 上重放(Replay)时都能得到相同的结果;而活动代码则没有此限制,可以安全地调用外部服务或执行 I/O 操作。

1.3.1 工作流与活动的关系

  • 编排与执行分离:工作流通过 ExecuteActivity 或 ExecuteLocalActivity 调用活动。工作流本身不执行具体的业务逻辑,只负责决定“何时”以及“在何种条件下”调用活动。
  • 超时与重试:工作流可以为每个活动单独配置 Schedule-To-Close Timeout、Start-To-Close Timeout 和 Heartbeat Timeout。当活动失败时,工作流可以根据预设的重试策略(Retry Policy)自动重新调度活动。
  • 结果传递:活动的返回值(Result)会被 Temporal Server 持久化,并作为事件写入工作流的历史记录中。工作流代码在 await 活动结果时,实际上是在等待该事件的出现。

1.3.2 任务队列的桥梁作用

  • 任务类型:任务队列承载两种类型的任务:Workflow Task(驱动工作流代码执行)和 Activity Task(驱动活动代码执行)。
  • 路由机制:Worker 在启动时会注册自己监听哪些任务队列。Temporal Server 根据任务队列名称将任务分发给对应的 Worker。这实现了 Worker 与任务之间的解耦。
  • 负载均衡:多个 Worker 可以监听同一个任务队列,Server 通过轮询(Poll)机制实现任务的负载均衡分发。

1.3.3 工作流执行的唯一性

  • 标识符:每个工作流执行由 Workflow ID 和 Run ID 共同唯一标识。Workflow ID 由业务方指定(如订单ID),Run ID 由 Server 自动生成。
  • 执行状态:工作流执行具有明确的状态机:Running、Completed、Failed、TimedOut、Terminated、ContinuedAsNew 和 Canceled。
  • 事件历史:工作流执行的每一次状态变更、每一个活动的调度与完成,都会被记录为一条不可变的事件(Event),追加到该执行实例的事件历史(Event History)中。这是 Temporal 实现可靠性和可恢复性的基石。

1.4 代码示例:工作流与活动的定义

以下是一个使用 Java SDK 的简单示例,展示如何定义一个工作流和一个活动,并建立它们之间的调用关系。

// 1. 定义活动接口
public interface PaymentActivity {
    String processPayment(String orderId, double amount);
}

// 2. 实现活动逻辑(非确定性代码)
public class PaymentActivityImpl implements PaymentActivity {
    @Override
    public String processPayment(String orderId, double amount) {
        // 这里可以安全地调用外部支付网关
        // 例如:httpClient.post(paymentGatewayUrl, payload);
        return "payment_success_" + orderId;
    }
}

// 3. 定义工作流接口
public interface OrderWorkflow {
    void startOrderProcessing(String orderId);
}

// 4. 实现工作流逻辑(确定性代码)
public class OrderWorkflowImpl implements OrderWorkflow {

    private final PaymentActivity paymentActivity =
            Workflow.newActivityStub(PaymentActivity.class,
                    ActivityOptions.newBuilder()
                            .setStartToCloseTimeout(Duration.ofSeconds(10))
                            .setRetryOptions(RetryOptions.newBuilder()
                                    .setMaximumAttempts(3)
                                    .build())
                            .build());

    @Override
    public void startOrderProcessing(String orderId) {
        // 工作流编排:调用活动
        String paymentResult = paymentActivity.processPayment(orderId, 99.99);
        // 根据活动结果决定后续流程
        if (paymentResult.startsWith("payment_success")) {
            // 可以继续调用其他活动,如发货
        } else {
            // 执行补偿逻辑
        }
    }
}

最佳实践:工作流代码中不应包含任何 I/O 操作、线程睡眠、随机数生成或系统时间获取。所有非确定性操作必须封装在活动中。这是保证工作流重放安全性的关键。

1.5 概念对比总结

对比维度 工作流 (Workflow) 活动 (Activity)
代码确定性 必须严格确定性 无限制(可包含非确定性代码)
执行时长 可长达数月甚至数年 通常较短(秒级到分钟级)
状态持久化 通过事件历史自动持久化 仅结果和错误信息被持久化
重试机制 工作流任务失败由 Server 自动重试 由工作流通过 RetryOptions 配置
主要职责 编排、决策、协调 执行具体的业务逻辑