我有一个使用在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团队进行自动重试是真正的答案,所以我们不必在代码中担心这一点吗?
答案 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查询...);
但是,仍然需要修改代码并更改每个查询。
最诚挚的问候,
徐明。