--- name: workflow-orchestration-patterns version: 1.0.0 license: MIT --- # 工作流编排模式 —— 详细模式与实操示例 ## 关键设计决策:工作流 vs 活动 **基本原则**(来源:temporal.io/blog/workflow-engine-principles): - **工作流** = 编排逻辑与决策 - **活动** = 外部交互(API、数据库、网络调用) ### 工作流(编排) **特征:** - 包含业务逻辑与协调 - **必须具有确定性**(相同输入 → 相同输出) - **不能**直接进行外部调用 - 状态在故障时自动保留 - 即使基础设施发生故障,也可运行数年 **工作流示例任务:** - 决定执行哪些步骤 - 处理补偿逻辑 - 管理超时与重试 - 协调子工作流 ### 活动(外部交互) **特征:** - 处理所有外部系统交互 - 可以是非确定性的(API 调用、数据库写入) - 内置超时与重试逻辑 - **必须是幂等的**(调用 N 次 = 调用一次) - 生命周期短(通常数秒至数分钟) **活动示例任务:** - 调用支付网关 API - 写入数据库 - 发送电子邮件或通知 - 查询外部服务 ### 设计决策框架 ``` 是否涉及外部系统?→ 活动 是否为编排/决策逻辑?→ 工作流 ``` ## 核心工作流模式 ### 1. Saga 模式与补偿 **目的**:实现分布式事务,具备回滚能力 **模式**(来源:temporal.io/blog/compensating-actions-part-of-a-complete-breakfast-with-sagas): ``` 每个步骤: 1. 在执行之前先注册补偿 2. 执行该步骤(通过活动) 3. 失败时,按相反顺序(后进先出)运行所有补偿 ``` **示例:支付工作流** 1. 预留库存(补偿:释放库存) 2. 扣款(补偿:退款) 3. 履约订单(补偿:取消履约) **关键要求:** - 补偿操作必须是幂等的 - 在执行步骤之前先注册补偿 - 按相反顺序运行补偿 - 优雅处理部分失败 ### 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()`(确定性随机数) - ✅ 纯函数与计算 - ✅ 调用活动(非确定性操作) ### 版本化策略 **挑战**:在旧执行仍在运行时修改工作流代码 **解决方案:** 1. **版本化 API**:使用 `workflow.get_version()` 进行安全变更 2. **新的工作流类型**:创建新工作流,将新执行路由到它 3. **向后兼容**:确保旧事件能正确重放 ## 弹性与错误处理 ### 重试策略 **默认行为**:Temporal 会无限重试活动 **配置重试:** - 初始重试间隔 - 退避系数(指数退避) - 最大间隔(重试延迟上限) - 最大尝试次数(最终失败) **不可重试的错误:** - 无效输入(校验失败) - 业务规则违反 - 永久性失败(资源未找到) ### 幂等性要求 **为何至关重要**(来源:docs.temporal.io/activities): - 活动可能被执行多次 - 网络故障会触发重试 - 重复执行必须是安全的 **实现策略:** - 幂等键(去重) - 先检查再执行 + 唯一约束 - 使用更新插入操作替代插入 - 跟踪已处理的请求 ID ### 活动心跳 **目的**:检测停滞的长时间运行活动 **模式:** - 活动定期发送心跳 - 包含进度信息 - 若未收到心跳则超时 - 支持基于进度的重试