工作流编排模式
掌握基于 Temporal 的工作流编排架构,涵盖构建可靠分布式系统的基本设计决策、弹性模式与最佳实践。
适用场景
- 正在处理工作流编排模式相关任务或工作流
- 需要工作流编排模式的指导、最佳实践或检查清单
不适用场景
- 任务与工作流编排模式无关
- 需要本范围之外的其他领域或工具
使用说明
- 明确目标、约束与所需输入。
- 应用相关最佳实践并验证结果。
- 提供可执行的步骤与验证方法。
- 如果需要详细示例,请打开
resources/implementation-playbook.md。
何时使用工作流编排
理想用例(来源:docs.temporal.io)
- 跨机器/服务/数据库的多步骤流程
- 需要 all-or-nothing 语义的分布式事务
- 长时间运行的工作流(数小时到数年),状态自动持久化
- 故障恢复必须能从上次成功步骤继续
- 业务流程:预订、订单、营销活动、审批
- 实体生命周期管理:库存跟踪、账户管理、购物车工作流
- 基础设施自动化:CI/CD 流水线、配置部署、发布
- 需要超时与升级机制的人机协同系统
不应使用的情况
- 简单的 CRUD 操作(使用直接 API 调用)
- 纯数据处理管道(使用 Airflow、批处理)
- 无状态的请求/响应(使用标准 API)
- 实时流式处理(使用 Kafka、事件处理器)
关键设计决策:工作流 vs 活动
核心原则(来源:temporal.io/blog/workflow-engine-principles):
- 工作流(Workflows) = 编排逻辑与决策
- 活动(Activities) = 外部交互(API、数据库、网络调用)
工作流(编排)
特征:
- 包含业务逻辑与协调
- 必须确定性(相同输入 → 相同输出)
- 不能直接执行外部调用
- 状态在故障间自动保留
- 即使基础设施故障也能运行多年
工作流任务示例:
- 决定执行哪些步骤
- 处理补偿逻辑
- 管理超时与重试
- 协调子工作流
活动(外部交互)
特征:
- 处理所有外部系统交互
- 可以非确定性(API 调用、数据库写入)
- 内置超时与重试逻辑
- 必须幂等(调用 N 次 = 调用 1 次)
- 短时运行(通常为秒级到分钟级)
活动任务示例:
- 调用支付网关 API
- 写入数据库
- 发送邮件或通知
- 查询外部服务
设计决策框架
是否涉及外部系统? → 活动
是否为编排/决策逻辑? → 工作流
核心工作流模式
1. Saga 模式与补偿
目的:实现具备回滚能力的分布式事务
模式(来源:temporal.io/blog/compensating-actions-part-of-a-complete-breakfast-with-sagas):
对每个步骤:
1. 在执行前注册补偿
2. 执行该步骤(通过活动)
3. 失败时,按相反顺序(LIFO)执行所有补偿
示例:支付工作流
- 预留库存(补偿:释放库存)
- 收取付款(补偿:退款)
- 履行订单(补偿:取消履约)
关键要求:
- 补偿必须幂等
- 在执行步骤之前注册补偿
- 按相反顺序执行补偿
- 优雅地处理部分失败
2. 实体工作流(Actor 模型)
目的:表示单个实体实例的长时间运行工作流
模式(来源:docs.temporal.io/evaluate/use-cases-design-patterns):
- 一次工作流执行 = 一个实体(购物车、账户、库存项)
- 工作流在实体生命周期内持续存在
- 接收信号以变更状态
- 支持查询当前状态
示例用例:
- 购物车(添加商品、结账、过期)
- 银行账户(存款、取款、余额查询)
- 产品库存(库存更新、预留)
优势:
- 封装实体行为
- 保证每个实体的一致性
- 天然的事件溯源
3. 扇出/扇入(并行执行)
目的:并行执行多个任务,汇总结果
模式:
- 生成子工作流或并行活动
- 等待全部完成
- 汇总结果
- 处理部分失败
伸缩规则(来源:temporal.io/blog/workflow-engine-principles):
- 不要对单个工作流进行伸缩
- 对于 100 万个任务:生成 1K 个子工作流 × 每个 1K 任务
- 保持每个工作流的边界
4. 异步回调模式
目的:等待外部事件或人工审批
模式:
- 工作流发送请求并等待信号
- 外部系统异步处理
- 发送信号以恢复工作流
- 工作流接收响应后继续
用例:
- 人工审批工作流
- Webhook 回调
- 长时间运行的外部进程
状态管理与确定性
自动状态保留
Temporal 的工作方式(来源:docs.temporal.io/workflows):
- 完整程序状态自动保留
- 事件历史记录每条命令与事件
- 崩溃后无缝恢复
- 应用程序恢复到故障前状态
确定性约束
工作流作为状态机执行:
- 重放行为必须保持一致
- 相同输入 → 每次输出完全相同
工作流中禁止(来源:docs.temporal.io/workflows):
- ❌ 线程、锁、同步原语
- ❌ 随机数生成(
random()) - ❌ 全局状态或静态变量
- ❌ 系统时间(
datetime.now()) - ❌ 直接文件 I/O 或网络调用
- ❌ 非确定性库
工作流中允许:
- ✅
workflow.now()(确定性时间) - ✅
workflow.random()(确定性随机数) - ✅ 纯函数与计算
- ✅ 调用活动(非确定性操作)
版本管理策略
挑战:在旧执行仍在运行时修改工作流代码
解决方案:
- 版本 API:使用
workflow.get_version()进行安全变更 - 新工作流类型:创建新工作流,将新执行路由到该工作流
- 向后兼容:确保旧事件能正确重放
弹性与错误处理
重试策略
默认行为:Temporal 会无限重试活动
配置重试:
- 初始重试间隔
- 退避系数(指数退避)
- 最大间隔(重试延迟上限)
- 最大尝试次数(最终失败)
不可重试错误:
- 输入无效(校验失败)
- 业务规则违反
- 永久性失败(资源未找到)
幂等性要求
为何关键(来源:docs.temporal.io/activities):
- 活动可能执行多次
- 网络故障会触发重试
- 重复执行必须安全
实现策略:
- 幂等键(去重)
- 先检查后执行,使用唯一约束
- 使用 Upsert 而非 Insert
- 跟踪已处理的请求 ID
活动心跳
目的:检测停滞的长时间运行活动
模式:
- 活动周期性发送心跳
- 包含进度信息
- 未收到心跳则超时
- 支持基于进度的重试
最佳实践
工作流设计
- 保持工作流聚焦 - 每个工作流单一职责
- 小型化工作流 - 使用子工作流以提升伸缩性
- 清晰边界 - 工作流负责编排,活动负责执行
- 本地测试 - 使用时间跳跃测试环境
活动设计
- 幂等操作 - 可安全重试
- 短时运行 - 秒级到分钟级,非小时级
- 超时配置 - 始终设置超时
- 长任务使用心跳 - 报告进度
- 错误处理 - 区分可重试与不可重试
常见陷阱
工作流违规:
- 使用
datetime.now()而非workflow.now() - 在工作流代码中使用线程或异步操作
- 在工作流中直接调用外部 API
- 工作流中存在非确定性逻辑
活动错误:
- 非幂等操作(无法处理重试)
- 缺少超时(活动无限运行)
- 没有错误分类(对校验错误也重试)
- 忽略负载限制(每个参数 2MB)
运维考量
监控:
- 工作流执行时长
- 活动失败率
- 重试次数与退避
- 待处理工作流数量
伸缩性:
- 使用 worker 进行水平伸缩
- 任务队列分区
- 子工作流分解
- 适当时进行活动批处理
额外资源
官方文档:
- Temporal 核心概念:docs.temporal.io/workflows
- 工作流模式:docs.temporal.io/evaluate/use-cases-design-patterns
- 最佳实践:docs.temporal.io/develop/best-practices
- Saga 模式:temporal.io/blog/saga-pattern-made-easy
关键原则:
- 工作流 = 编排,活动 = 外部调用
- 确定性对工作流而言不可妥协
- 幂等性对活动至关重要
- 状态保留是自动的
- 为故障与恢复而设计
限制
- 仅在任务明确符合上述范围时使用本技能。
- 不要将输出视为环境特定验证、测试或专家审查的替代品。
- 如果缺少所需输入、权限、安全边界或成功标准,请停止并寻求澄清。