在SQL Azure上重试LINQ-TO-SQL逻辑 - 高效实现?

时间:2012-04-17 22:10:41

标签: linq-to-sql azure-sql-database

我有一个使用在Azure中运行的LINQ-TO-SQL的相当大的Web应用程序,我遇到来自SQL-Azure的Transient错误,因此需要实现重试。我知道Transient Fault Handling Framework以及几个提供示例如何使用它的网站,但看起来你必须将每个LINQ查询包装成类似于此的内容:

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

在我的数据层中有数百个LINQ查询,这看起来非常混乱,而且很多时候查询在枚举结果之前并没有实际执行。例如,我的数据层中的大多数函数都返回IQueryable&lt;&gt;直到业务层,(这使得它们比返回List更灵活)。因此,这意味着您必须使用数据库重试逻辑来丢弃业务逻辑层 - 这很丑陋。

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

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

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

2 个答案:

答案 0 :(得分:1)

在需要实现这样的东西之后,我继续把它变成了一个库:https://github.com/daveaglick/LinqToSqlRetry(麻省理工学院许可并在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对象的函数是根据用法提供的。这只是让您了解重试循环期间发生了什么。只需查看存储库以获取更多信息。

答案 1 :(得分:0)

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

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

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

Result = QueryWithRetry(...这里是LINQ查询...);

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

最诚挚的问候,

徐明。