一、为什么需要重试机制

想象一下这个场景:你点外卖时网络卡顿,第一次下单失败,但系统自动帮你重新提交,最终成功下单——这就是重试机制的日常版。在WCF服务调用中,网络波动、服务短暂不可用等情况就像外卖下单时的网络问题,重试机制能自动帮你"多试几次",避免手动处理这类小故障。

典型场景

  • 跨机房调用时网络闪断
  • 数据库连接池短暂耗尽
  • 第三方服务偶尔超时

二、基础重试方案:手动实现

(技术栈:C# + WCF)

// 示例1:最基础的重试循环
public static T CallWithRetry<T>(Func<T> action, int maxRetries = 3)
{
    int retryCount = 0;
    while (true)
    {
        try 
        {
            return action(); // 尝试执行操作
        }
        catch (CommunicationException ex) // 只捕获网络类异常
        {
            if (retryCount >= maxRetries)
                throw; // 达到最大重试次数后抛出
            
            retryCount++;
            Thread.Sleep(1000 * retryCount); // 延迟时间逐步增加
        }
    }
}

// 使用示例
var result = CallWithRetry(() => 
{
    using (var client = new MyServiceClient())
    {
        return client.GetData(123); // WCF服务调用
    }
});

关键点说明

  1. 限定只重试网络通信异常(CommunicationException)
  2. 采用"指数退避"延迟(每次等待时间递增)
  3. 需要明确最大重试次数,避免无限循环

三、进阶方案:Polly整合

(技术栈:C# + Polly库)

Polly是.NET生态中专门处理弹性策略的库,可以更优雅地实现重试:

// 示例2:使用Polly实现智能重试
var retryPolicy = Policy
    .Handle<CommunicationException>() // 指定异常类型
    .WaitAndRetry(
        retryCount: 5, 
        sleepDurationProvider: attempt => TimeSpan.FromSeconds(attempt * 2), // 退避策略
        onRetry: (ex, delay) => Console.WriteLine($"重试中,延迟{delay}") // 日志记录
    );

retryPolicy.Execute(() => 
{
    using (var client = new MyServiceClient())
    {
        return client.ProcessOrder(order); // 业务方法调用
    }
});

Polly的优势

  • 内置多种重试策略(恒定间隔、指数退避等)
  • 支持熔断机制等高级特性
  • 可组合多种策略(如重试+超时)

四、生产环境注意事项

  1. 幂等性设计
    如果服务不是天然幂等的,需要在重试时加入防重复逻辑:

    // 示例3:带幂等令牌的重试
    var requestId = Guid.NewGuid().ToString();
    retryPolicy.Execute(() => 
    {
        service.ProcessPayment(requestId, amount); // 服务端通过requestId去重
    });
    
  2. 重试日志记录
    建议记录每次重试的异常和延迟信息,便于后期分析:

    .OnRetry((ex, delay, ctx) => 
    {
        logger.Warn($"第{ctx["retryCount"]}次重试,原因:{ex.Message}");
    })
    
  3. 不要重试的情况

    • 认证失败(401错误)
    • 权限不足(403错误)
    • 业务逻辑错误(如参数校验失败)

五、与其他技术的协作

当WCF服务需要访问数据库时,建议采用分层重试策略:

// 示例4:分层重试组合
var dbPolicy = Policy // 数据库层策略
    .Handle<SqlException>()
    .WaitAndRetry(2, attempt => TimeSpan.FromMilliseconds(500));

var wcfPolicy = Policy // 服务调用层策略
    .Handle<CommunicationException>()
    .WaitAndRetry(3, attempt => TimeSpan.FromSeconds(attempt));

// 策略组合执行
wcfPolicy.Execute(() => 
{
    dbPolicy.Execute(() => 
    {
        // 先执行数据库操作
        var data = db.Query("SELECT...");
        
        // 再调用WCF服务
        using (var client = new MyServiceClient())
        {
            return client.SubmitData(data);
        }
    });
});

六、方案对比与选型建议

方案 适用场景 优点 缺点
手动实现 简单场景、少量调用 无第三方依赖 功能简单,维护成本高
Polly 复杂业务、生产环境 功能丰富,可扩展性强 需要学习新库

对于新项目,建议直接使用Polly;如果是遗留系统小范围改造,可以手动实现基础版本。

七、总结

处理WCF调用失败就像应对城市交通拥堵——无法完全避免,但可以通过"绕行方案"(重试机制)提高成功率。关键要记住:

  1. 区分可重试和不可重试的异常
  2. 重试次数和延迟时间需要合理设置
  3. 生产环境一定要考虑幂等性问题

下次遇到网络波动导致的调用失败,不妨试试这些方案,让你的服务像老司机一样"稳"起来!