6

我有一个在 Azure 中运行的使用 LINQ-TO-SQL 的相当大的 Web 应用程序,我遇到了来自 SQL-Azure 的瞬态错误,因此需要实现重试。我知道瞬态故障处理框架和几个提供如何使用它的示例的站点,但看起来您必须将每个 LINQ 查询包装在类似于以下内容的内容中:

RetryPolicy retry = new RetryPolicy<MyRetryStrategy>(5, TimeSpan.FromSeconds(5));
Result = retry.ExecuteAction(() =>
{
   … LINQ query here...
});

在我的数据层中有数百个 LINQ 查询,这看起来真的很混乱,而且很多时候查询在结果被枚举之前并没有真正执行。例如,我的数据层中的大多数函数都将 IQueryable<> 返回到业务层(这使得它们比返回列表更灵活)。所以这意味着你必须用数据库重试逻辑乱扔你的业务逻辑层——丑陋。

所以我想为了将重试逻辑保留在数据层中,我必须将 .ToList()'s 放在我的所有查询中,以便它们在那里执行,而不是在上面的层中。

我真的希望有一种方法可以在某些基类中实现重试逻辑,而不必更改我的所有查询。好像EF也会有这个问题。

尝试与 SQL-Azure 团队进行自动重试是否是真正的答案,所以我们不必在代码中担心这一点?

4

2 回答 2

1

在需要实现类似这样的东西之后,我继续将它变成了一个库:https ://github.com/daveaglick/LinqToSqlRetry (MIT 许可并在 NuGet 上可用)。

您可以SubmitChanges()改写来重试调用SubmitChangesRetry()

using(var context = new MyDbContext())
{
  context.Items.InsertOnSubmit(new Item { Name = "ABC" });
  context.SubmitChangesRetry();
}

您还可以使用Retry()扩展方法重试查询:

using(var context = new MyDbContext())
{
  int count = context.Items.Where(x => x.Name == "ABC").Retry().Count();
}

具体的重试逻辑由策略控制。在后台,重试机制如下所示:

int retryCount = 0;
while (true)
{
    try
    {
        return func();
    }
    catch (Exception ex)
    {
        TimeSpan? interval = retryPolicy.ShouldRetry(retryCount, ex);
        if (!interval.HasValue)
        {
            throw;
        }
        Thread.Sleep(interval.Value);
    }
    retryCount++;
}

了解调用中的函数func()retryPolicy对象是根据使用情况提供的。这只是让您了解重试循环期间发生了什么。只需在存储库中查看更多信息。

于 2014-12-22T22:49:29.420 回答
0

我不知道一个好的解决方案,因为 LINQ to SQL 不允许我们拦截查询。但是一点代码重构可能会有所帮助。类似的东西(伪代码):

public Result QueryWithRetry(IQueryable query)
{
      RetryPolicy retry = new RetryPolicy<MyRetryStrategy>(5, TimeSpan.FromSeconds(5)); 
     (() => 
     { 
       return retry.ExecuteAction(query);
     }
}

现在调用这个方法稍微容易一些:

结果 = QueryWithRetry(... LINQ 查询在这里...);

但是,仍然需要修改您的代码并更改每个查询。

此致,

明旭。

于 2012-04-18T08:12:02.753 回答