共计 2347 个字符,预计需要花费 6 分钟才能阅读完成。
引言
在微服务开发中,我们经常会遇到需要协调多个函数调用的情况。比如一个订单处理流程可能需要依次调用库存检查、支付处理、物流创建等多个服务。传统的实现方式往往会导致代码臃肿、难以维护:

- 嵌套的回调地狱让代码可读性急剧下降
- 错误处理逻辑分散在各个层级
- 添加新步骤需要重构整个调用链
- 重试机制实现困难且不统一
技术选型:Workflow Core vs Azure Durable Functions
在.NET 生态中,主要有两个工作流引擎选择:
- Workflow Core:
- 开源免费,可自托管
- 轻量级(核心库仅 200KB)
- 支持自定义持久化提供程序
-
适合需要深度定制的场景
-
Azure Durable Functions:
- 微软云原生解决方案
- 自动处理扩展和负载均衡
- 内置与 Azure 服务集成
- 适合已经使用 Azure 云服务的团队
对于需要私有化部署或特殊定制的项目,Workflow Core 通常是更好的选择。
核心实现
1. 定义工作流 DSL
Workflow Core 使用流畅 API 定义工作流。以下是一个包含条件分支和并行执行的示例:
public class OrderProcessingWorkflow : IWorkflow<OrderData>
{public void Build(IWorkflowBuilder<OrderData> builder)
{
builder
.StartWith<ValidateOrderStep>()
.If(data => data.NeedsApproval).Do(then => then
.StartWith<ManagerApprovalStep>())
.Parallel()
.Do(branch1 => branch1
.StartWith<ProcessPaymentStep>())
.Do(branch2 => branch2
.StartWith<ReserveInventoryStep>())
.Join()
.Then<CreateShipmentStep>()
.OnError(WorkflowErrorHandling.Retry, TimeSpan.FromMinutes(1));
}
}
2. 上下文数据传递
工作流步骤间通过共享上下文对象传递数据:
public class ProcessPaymentStep : StepBody
{public OrderData Order { get; set;}
public override ExecutionResult Run(IStepExecutionContext context)
{
// 从上下文中获取数据
var amount = Order.TotalAmount;
// 处理支付逻辑...
// 将结果存回上下文
Order.PaymentId = "PAY123";
return ExecutionResult.Next();}
}
3. 完整的异常处理示例
public class ReserveInventoryStep : StepBody
{public OrderData Order { get; set;}
public override ExecutionResult Run(IStepExecutionContext context)
{
try
{
// 调用库存服务
if (!InventoryService.Reserve(Order.Items))
{
// 业务异常时终止工作流
return ExecutionResult.Fail("库存不足");
}
return ExecutionResult.Next();}
catch (Exception ex)
{
// 系统异常时触发重试
context.Workflow.Status = WorkflowStatus.Runnable;
throw;
}
}
}
生产级考量
工作流持久化
Workflow Core 支持多种持久化后端(SQL Server、MongoDB 等)。序列化性能对比:
| 序列化方式 | 平均耗时(100KB 数据) | 存储大小 |
|---|---|---|
| JSON.NET | 12ms | 98KB |
| MessagePack | 5ms | 45KB |
| Protobuf | 7ms | 38KB |
对于高吞吐场景,推荐使用二进制序列化格式。
补偿事务实现
补偿模式 (Compensation) 不同于简单的回滚(Rollback),它是一组明确定义的逆向操作:
builder
.StartWith<CreateOrderStep>()
.CompensateWith<CancelOrderStep>()
.Then<ProcessPaymentStep>()
.CompensateWith<RefundPaymentStep>();
补偿步骤应该实现幂等性,因为它们可能被多次执行。
避坑指南
- 循环依赖检测
- 使用
WorkflowValidator.Validate方法检查工作流定义 -
运行时检测到循环时会抛出
WorkflowDefinitionException -
超时控制
var host = new WorkflowHost(...); host.RegisterWorkflow<OrderProcessingWorkflow>(new WorkflowOptions { ErrorBehavior = WorkflowErrorHandling.Suspend, MaxRetryAttempts = 3, DefaultStepTimeout = TimeSpan.FromMinutes(5) });
总结与思考
通过 Workflow Core,我们成功将业务逻辑与流程控制解耦,获得了以下优势:
- 可视化的工作流定义
- 内置的错误处理和重试机制
- 灵活的补偿事务支持
最后留一个思考题:如何扩展当前方案支持 Saga 分布式事务模式?可以考虑:
- 为每个工作流步骤添加分布式锁
- 实现跨服务的补偿事务协调器
- 引入事件溯源模式记录状态变更
欢迎在评论区分享你的解决方案!
正文完
