共计 2474 个字符,预计需要花费 7 分钟才能阅读完成。
背景痛点
在分布式系统开发中,任务编排一直是个头疼的问题。特别是当业务流程涉及多个微服务、需要长时间运行、或者要求高可靠性时,传统的解决方案往往显得力不从心。

-
任务编排复杂性:随着业务逻辑越来越复杂,简单的串行 / 并行任务调度已经无法满足需求。我们需要考虑任务依赖、条件分支、循环等复杂流程控制。
-
错误恢复困难:当某个步骤失败时,整个流程如何优雅地恢复?传统方案要么重试整个流程(浪费资源),要么需要手动干预(运维成本高)。
-
状态管理缺失:长时间运行的业务流程需要持久化中间状态,传统方案要么依赖数据库(复杂度高),要么完全丢失上下文(可靠性差)。
技术对比
在任务编排领域,我们有几个常见的选择:
-
Airflow/Luigi:适合批处理任务调度,但对长时间运行(几天甚至几个月)的流程支持有限,且错误恢复机制较弱。
-
Cadence:专为长时间运行、高可靠的业务流程设计,提供自动错误恢复、状态持久化等核心功能。
-
关键优势:
- 自动持久化工作流状态,即使进程重启也能继续执行
- 内置重试机制,可配置重试策略
- 支持信号机制,实现工作流的动态控制
核心实现
工作流定义
Cadence 工作流通常包含以下几个核心部分:
-
工作流接口定义:声明工作流的入口方法和信号方法
-
工作流实现:包含具体的业务流程逻辑
-
活动定义:封装具体的业务操作
活动任务
活动 (Activity) 是工作流中的基本执行单元,每个活动应该:
- 实现单一职责
- 包含明确的超时设置
- 处理好幂等性
信号机制
信号 (Signal) 允许外部系统与运行中的工作流交互,常见使用场景:
- 人工审批结果通知
- 外部系统回调
- 流程控制指令(暂停 / 继续 / 取消)
代码示例(Go 语言)
下面是一个完整的订单处理工作流示例:
// 工作流接口定义
type OrderProcessingWorkflow interface {Execute(ctx workflow.Context, orderID string) error
}
// 工作流实现
func OrderProcessingWorkflowImpl(ctx workflow.Context, orderID string) error {
// 1. 验证订单
err := workflow.ExecuteActivity(ctx, ValidateOrderActivity, orderID).Get(ctx, nil)
if err != nil {return err}
// 2. 等待支付完成(使用信号机制)var paymentCompleted bool
signalChan := workflow.GetSignalChannel(ctx, "paymentCompleted")
selector := workflow.NewSelector(ctx)
selector.AddReceive(signalChan, func(c workflow.ReceiveChannel, more bool) {c.Receive(ctx, &paymentCompleted)
})
selector.Select(ctx) // 阻塞等待信号
if !paymentCompleted {return errors.New("payment not completed")
}
// 3. 处理订单(带重试机制)ao := workflow.ActivityOptions{
StartToCloseTimeout: time.Minute * 5,
RetryPolicy: &temporal.RetryPolicy{
InitialInterval: time.Second,
BackoffCoefficient: 2.0,
MaximumInterval: time.Minute,
MaximumAttempts: 3,
},
}
ctx = workflow.WithActivityOptions(ctx, ao)
return workflow.ExecuteActivity(ctx, ProcessOrderActivity, orderID).Get(ctx, nil)
}
// 验证订单活动
func ValidateOrderActivity(ctx context.Context, orderID string) error {
// 实现订单验证逻辑
return nil
}
// 处理订单活动
func ProcessOrderActivity(ctx context.Context, orderID string) error {
// 实现订单处理逻辑
return nil
}
生产考量
版本升级
工作流代码升级时需要特别注意:
- 使用
workflow.GetVersion进行版本检查 - 为重大变更创建新的工作流类型
- 逐步迁移现有工作流实例
历史数据
- 设置合理的历史保留期限(通常 7 -30 天)
- 对重要业务数据单独归档
- 定期清理已完成的工作流
监控指标
关键监控指标包括:
- 工作流执行耗时分布
- 活动失败率
- 信号处理延迟
- 工作流堆积数量
避坑指南
随机数问题
在工作流代码中避免使用随机数,因为工作流可能会重放执行。如果需要随机性,应该:
- 在活动中生成随机数
- 使用确定性随机源
幂等性处理
所有活动必须实现幂等,常见策略:
- 使用唯一业务 ID
- 检查前置状态
- 实现乐观锁
状态查询优化
避免频繁查询工作流状态,可以:
- 使用信号回传状态
- 设置状态变更事件
- 缓存查询结果
互动环节
扩展思考
假设你需要实现一个电商平台的订单自动取消功能:
- 用户下单后 30 分钟未支付自动取消
- 支持管理员手动提前取消
- 取消后需要释放库存
思考如何用 Cadence 实现这个需求?
本地实验
快速搭建本地开发环境:
-
下载 Cadence 服务端:
docker run --rm -p 7933:7933 -p 7934:7934 -p 7935:7935 ubercadence/local:latest -
安装客户端 SDK:
go get go.temporal.io/sdk -
运行示例工作流
总结
Cadence 为复杂业务流程提供了强大的编排能力,特别是对于需要长时间运行、高可靠性的场景。通过合理设计工作流、正确处理错误和幂等性,可以构建出生产级可靠的分布式系统。
建议从简单的工作流开始,逐步熟悉各种高级特性,最终实现复杂的业务场景编排。
