2012-04-17 4 views
6

Ich habe eine ziemlich große Web-Anwendung mit LINQ-TO-SQL in Azure ausgeführt, und ich habe Transient Fehler von SQL-Azure und müssen daher Wiederholungen implementieren. Ich bin mir bewusst, die Transient Fault Handling Framework und mehr Websites, die Beispiele geben, wie es zu benutzen, aber es sieht aus wie Sie jeden Ihrer LINQ-Abfragen in etwas ähnlich wie diese wickeln haben:Retry Logik für LINQ-TO-SQL auf SQL Azure - Effiziente Implementierungen?

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

Mit Hunderten von LINQ-Abfragen In meiner Datenschicht scheint dies wirklich chaotisch zu sein, und die Tatsache, dass die Abfrage oft nicht ausgeführt wird, bis die Ergebnisse aufgelistet sind. Zum Beispiel geben die meisten meiner Funktionen in meiner Datenschicht ein IQueryable <> an die Business-Schicht zurück (was sie flexibler macht, als eine Liste zurückzugeben). Das würde bedeuten, dass Sie Ihre Business-Logik-Schicht mit der Datenbank-Wiederholungslogik verwischen müssen - hässlich.

Also ich denke, um die Wiederholungslogik in der Datenschicht zu behalten, müsste ich.ToList() auf alle meine Abfragen setzen, damit sie genau dort ausgeführt werden, und nicht in der darüber liegenden Schicht.

Ich wünschte wirklich, es gäbe eine Möglichkeit, Wiederholungslogik in einer Basisklasse zu implementieren und nicht alle meine Abfragen zu ändern. Sieht so aus, als hätte EF dieses Problem auch.

Ist die wirkliche Antwort zu versuchen und das SQL-Azure-Team zu sprechen, um die automatischen Wiederholungen zu machen, also müssen wir uns in unserem Code nicht darum kümmern?

Antwort

0

Mir ist keine gute Lösung bekannt, da LINQ to SQL es uns nicht erlaubt, Abfragen abzufangen. Aber ein kleiner Code-Refactor kann helfen. So etwas wie (Pseudocode):

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

Jetzt ist es etwas einfacher, diese Methode aufzurufen:

Ergebnis = QueryWithRetry (... LINQ-Abfrage hier ...);

Es ist jedoch immer noch erforderlich, den Code zu ändern und jede Abfrage zu ändern.

Mit besten Grüßen,

Ming Xu.

+0

Das hilft ein wenig, aber müsste ich mich immer noch nicht um die Abfragen kümmern, die erst später im Code ausgeführt werden, in dem sie aufgelistet sind? Daher müsste ich wirklich jede Abfrage untersuchen und herausfinden, wo die Datenbank tatsächlich aufgerufen wird. – PeteShack

+0

Entschuldigung, ich kann dich nicht sehr gut verstehen. Meinst du, du bist besorgt, wenn etwas schief geht, wird es schwieriger sein, die Ursache des Problems zu finden, weil die Abfrage in ein Wiederholungs-Framework eingebettet wurde? In diesem Fall möchte ich vorschlagen, dass Sie einen Breakpoint bei retry.ExecuteAction setzen und den Code durchlaufen. –

+0

Nein, ich meine nur, dass das Hinzufügen der Wiederholungslogik zu einer bestehenden App mit Hunderten von Abfragen eine schwierige Aufgabe ist - hauptsächlich weil der Datenbankaufruf nicht unbedingt in der linq-to-sql-Abfrage in der Datenschicht erfolgt. Die Ausführung der Abfrage kann verzögert werden, bis IQueryable tatsächlich aufgelistet wird. Dies kann in der Business-Schicht passieren. Es scheint einfach keine saubere Lösung für dieses Problem zu sein. – PeteShack

1

Nachdem ich so etwas implementieren musste, ging ich weiter und machte es zu einer Bibliothek: https://github.com/daveaglick/LinqToSqlRetry (MIT lizenziert und auf NuGet verfügbar).

können Sie SubmitChanges() Anrufe wiederholen durch SubmitChangesRetry() Schreiben statt:

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

Sie können auch Abfragen wiederholen, indem die Retry() Erweiterung Methode:

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

Die spezifische Wiederholungslogik durch eine Politik steuerbar ist. Unter der Haube sieht der Wiederholungsmechanismus wie:

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++; 
} 

Verstehen Sie, dass die Funktion in dem Aufruf von func() und das retryPolicy Objekt basiert auf Nutzung zur Verfügung gestellt. Dies gibt Ihnen nur eine Vorstellung davon, was während der Wiederholungsschleife vor sich geht. Sehen Sie im Repository nach, um weitere Informationen zu erhalten.