2012-04-17 60 views
6

我有一個使用在Azure中運行的LINQ-TO-SQL的相當大的Web應用程序,並且遇到來自SQL Azure的瞬態錯誤,因此需要實施重試。我知道了Transient Fault Handling Framework和幾個網站,讓例子來說明如何使用它,但它看起來像你有你的LINQ查詢中的每一個包裹在類似這樣的東西:SQL Azure上LINQ-TO-SQL的重試邏輯 - 高效實現?

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

數以百計LINQ查詢在我的數據層中,這看起來非常混亂,再加上這樣的事實:查詢在枚舉結果之前並未實際執行。例如,我的數據層中的大部分函數都返回一個IQueryable直到業務層(這使得它們比返回List更加靈活)。所以那意味着你不得不用數據庫重試邏輯來拋棄你的業務邏輯層 - 醜陋。所以我想爲了保持數據層中的重試邏輯,我必須在所有查詢中放置.ToList(),以便它們在那裏執行,而不是在上面的圖層中執行。

我真的希望有一種方法可以在某些基類中實現重試邏輯,而不必更改所有的查詢。似乎EF也會有這個問題。

真正的答案是嘗試與SQL-Azure團隊進行自動重試,因此我們不必擔心在我們的代碼中出現這種情況嗎?

回答

0

我不知道一個好的解決方案,因爲LINQ to SQL不允許我們攔截查詢。但是一些代碼重構可能會有所幫助。像(僞代碼)的東西:

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

現在是稍微容易調用這個方法:

結果= QueryWithRetry(... LINQ查詢這裏...);

但是,仍然需要修改代碼並更改每個查詢。

最好的問候,

Ming Xu。

+0

這會有所幫助,但是我不需要擔心在枚舉代碼後纔會實際執行的查詢嗎?因此,我必須真正調查每個查詢並找出數據庫實際被調用的位置。 – PeteShack 2012-04-18 13:28:08

+0

對不起,我無法很好地理解你。你的意思是你擔心出現問題,因爲將查詢包裝在重試框架中會更難找到問題的根源?在這種情況下,我想建議你在retry.ExecuteAction上設置一個斷點,並逐步完成代碼。 – 2012-04-19 07:42:32

+0

不,我的意思是將重試邏輯添加到具有數百個查詢的現有應用程序將是一項艱鉅的任務 - 主要是因爲數據庫調用不一定發生在數據層的linq-to-sql查詢中。查詢的執行可能會延遲,直到IQueryable被實際枚舉 - 這可能發生在業務層。這似乎不是一個乾淨的解決方案,這個問題。 – PeteShack 2012-04-19 13:25:37

1

在需要實現這樣的事情之後,我繼續做了一個庫:https://github.com/daveaglick/LinqToSqlRetry(麻省理工學院許可並可在NuGet上獲得)。

您可以通過編寫SubmitChangesRetry()而不是重試SubmitChanges()電話:

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對象的功能。這只是讓你知道重試循環過程中發生了什麼。只需查看存儲庫以獲取更多信息。