Verbindungsresilienz und -wiederholungslogik
Hinweis
Nur EF6 und höher: Die Features, APIs usw., die auf dieser Seite erläutert werden, wurden in Entity Framework 6 eingeführt. Wenn Sie eine frühere Version verwenden, gelten manche Informationen nicht.
Anwendungen, die eine Verbindung mit einem Datenbankserver herstellen, sind aufgrund von Back-End-Fehlern und Netzwerkinstabilität immer für Verbindungsunterbrechungen anfällig. In einer LAN-basierten Umgebung, die mit dedizierten Datenbankservern arbeitet, sind diese Fehler jedoch eher selten, sodass häufig keine zusätzliche Logik zur Behandlung solcher Fehler erforderlich ist. Mit der Zunahme cloudbasierter Datenbankserver wie Windows Azure SQL-Datenbank und von Verbindungen über weniger zuverlässige Netzwerke kommt es inzwischen häufiger, dass Verbindungsunterbrechungen auftreten. Diese Tatsache kann auf Abwehrtechniken, mit denen Clouddatenbanken die Fairness des Dienstes sicherstellen (z. B. Verbindungsdrosselung), oder auf Instabilität im Netzwerk zurückzuführen sein, wodurch zeitweilige Timeouts und andere vorübergehende Fehler verursacht werden.
Verbindungsresilienz bezieht sich auf die Möglichkeit, dass EF alle Befehle automatisch wiederholen kann, die aufgrund solcher Verbindungsunterbrechungen fehlschlagen.
Ausführungsstrategien
Die Verbindungswiederholung wird durch eine Implementierung der IDbExecutionStrategy-Schnittstelle sichergestellt. Implementierungen der IDbExecutionStrategy übernehmen einen Vorgang. Falls eine Ausnahme auftritt, ermitteln Sie, ob ein Wiederholungsvorgang angemessen ist, und versuchen es erneut, sofern dies der Fall ist. Es gibt vier Ausführungsstrategien, die mit EF ausgeliefert werden:
- DefaultExecutionStrategy: Bei dieser Ausführungsstrategie werden Vorgänge nicht erneut ausgeführt. Dies ist die Standardeinstellung für andere Datenbanken als SQL Server.
- DefaultSqlExecutionStrategy: Dies ist eine interne Ausführungsstrategie, die standardmäßig verwendet wird. Diese Strategie versucht keinerlei Wiederholung. Sie schließt jedoch alle Ausnahmen ein, die vorübergehend sein könnten, um Benutzer darüber zu informieren, dass sie erwägen sollten, Verbindungsresilienz zu aktivieren.
- DbExecutionStrategy: Diese Klasse eignet sich als Basisklasse für andere Ausführungsstrategien, einschließlich ihrer benutzerdefinierten Strategien. Sie implementiert eine exponentielle Wiederholungsrichtlinie, bei der der anfängliche Wiederholungsversuch ohne Verzögerung erfolgt, und die Verzögerung exponentiell steigt, bis die maximale Wiederholungsanzahl erreicht wurde. Diese Klasse verfügt über eine abstrakte ShouldRetryOn-Methode, die in abgeleiteten Ausführungsstrategien implementiert werden kann, um zu steuern, welche Ausnahmen wiederholt werden sollen.
- SqlAzureExecutionStrategy: Diese Ausführungsstrategie erbt von DbExecutionStrategy und versucht bei solchen Ausnahmen, die beim Arbeiten mit Azure SQL-Datenbank bekanntermaßen vorübergehend sein können, eine erneute Ausführung.
Hinweis
Die Ausführungsstrategien 2 und 4 sind im SQL Server-Anbieter enthalten, den der Lieferumfang von EF umfasst. Er befindet sich in der EntityFramework.SqlServer-Assembly und ist für die Arbeit mit SQL Server konzipiert.
Aktivieren einer Ausführungsstrategie
Die einfachste Möglichkeit, EF anzuweisen, eine Ausführungsstrategie zu verwenden, ist die SetExecutionStrategy-Methode der DbConfiguration-Klasse:
public class MyConfiguration : DbConfiguration
{
public MyConfiguration()
{
SetExecutionStrategy("System.Data.SqlClient", () => new SqlAzureExecutionStrategy());
}
}
Dieser Code weist EF an, beim Herstellen einer Verbindung mit SQL Server die SqlAzureExecutionStrategy zu verwenden.
Konfigurieren der Ausführungsstrategie
Der Konstruktor von SqlAzureExecutionStrategy kann zwei Parameter akzeptieren: MaxRetryCount und MaxDelay. MaxRetryCount steht für die Anzahl der Wiederholungsversuche der Strategie. MaxDelay ist ein Zeitraum (TimeSpan), der für die maximale Verzögerung zwischen Wiederholungen steht, die von der Ausführungsstrategie verwendet werden.
Um beispielsweise die maximale Anzahl von Wiederholungsversuchen auf 1 und die maximale Verzögerung auf 30 Sekunden festzulegen, würden Sie Folgendes ausführen:
public class MyConfiguration : DbConfiguration
{
public MyConfiguration()
{
SetExecutionStrategy(
"System.Data.SqlClient",
() => new SqlAzureExecutionStrategy(1, TimeSpan.FromSeconds(30)));
}
}
Die SqlAzureExecutionStrategy wird sofort einen neuen Versuch unternehmen, wenn ein vorübergehender Fehler auftritt. Die Verzögerung zwischen den Wiederholungsversuchen wird jedoch immer länger, bis entweder die maximale Wiederholungsgrenze überschritten wird, oder die Gesamtzeit die maximale Verzögerung erreicht.
Die Ausführungsstrategien unternehmen nur bei einer begrenzten Anzahl von Ausnahmen Wiederholungsversuche. Dabei handelt es sich um solche, die normalerweise vorübergehend sind. Andere Fehler müssen Sie weiterhin selbst beheben. Außerdem müssen Sie die RetryLimitExceeded-Ausnahme für den Fall abfangen, dass ein Fehler nicht vorübergehend ist oder zu lange braucht, um sich selbst zu beheben.
Es gibt einige bekannte Einschränkungen bei der Verwendung einer Wiederholungsausführungsstrategie:
Streamingabfragen werden nicht unterstützt.
Standardmäßig puffern EF6 und höhere Versionen Abfrageergebnisse, anstatt sie zu streamen. Wenn Sie Ergebnisse streamen möchten, können Sie die AsStreaming-Methode verwenden, um eine LINQ to Entities-Abfrage in Streaming abzuändern.
using (var db = new BloggingContext())
{
var query = (from b in db.Blogs
orderby b.Url
select b).AsStreaming();
}
}
Streaming wird nicht unterstützt, wenn eine Wiederholungsausführungsstrategie registriert wird. Diese Einschränkung ist vorhanden, da die Verbindung mitten beim Zurückgeben der Ergebnisse unterbrochen werden könnte. Wenn dies geschieht, muss EF die gesamte Abfrage erneut ausführen, hat aber keine zuverlässige Möglichkeit, zu wissen, welche Ergebnisse bereits zurückgegeben wurden (Daten können sich seit dem Senden der ursprünglichen Abfrage geändert haben, Ergebnisse können in einer anderen Reihenfolge zurückgegeben werden, Ergebnisse haben möglicherweise keinen eindeutigen Bezeichner usw.).
Vom Benutzer initiierte Transaktionen werden nicht unterstützt.
Wenn Sie eine Ausführungsstrategie konfiguriert haben, die zu Wiederholungen führt, gibt es einige Einschränkungen hinsichtlich der Verwendung von Transaktionen.
Standardmäßig führt EF alle Datenbankaktualisierungen innerhalb einer Transaktion aus. Sie müssen nichts tun, um dies zu aktivieren, EF führt dies immer automatisch aus.
Im folgenden Code wird SaveChanges beispielsweise automatisch innerhalb einer Transaktion ausgeführt. Wenn SaveChanges nach dem Einfügen einer neuen Sites fehlschlagen würde, würde die Transaktion zurückgesetzt und keine Änderungen auf die Datenbank angewendet werden. Der Kontext befindet sich ebenfalls in einem Zustand, in dem SaveChanges noch einmal aufgerufen werden kann, um zu versuchen, die Änderungen erneut anzuwenden.
using (var db = new BloggingContext())
{
db.Blogs.Add(new Site { Url = "http://msdn.com/data/ef" });
db.Blogs.Add(new Site { Url = "http://blogs.msdn.com/adonet" });
db.SaveChanges();
}
Wenn Sie keine Wiederholungsausführungsstrategie verwenden, können Sie mehrere Vorgänge in einer einzelnen Transaktion umschließen. Mit dem folgenden Code werden beispielsweise zwei SaveChanges-Aufrufe in einer einzelnen Transaktion umschlossen. Wenn ein Teil der beiden Vorgänge fehlschlägt, werden keine Änderungen angewendet.
using (var db = new BloggingContext())
{
using (var trn = db.Database.BeginTransaction())
{
db.Blogs.Add(new Site { Url = "http://msdn.com/data/ef" });
db.Blogs.Add(new Site { Url = "http://blogs.msdn.com/adonet" });
db.SaveChanges();
db.Blogs.Add(new Site { Url = "http://twitter.com/efmagicunicorns" });
db.SaveChanges();
trn.Commit();
}
}
Dies wird nicht unterstützt, wenn Sie eine Wiederholungsausführungsstrategie verwenden, da EF nicht bekannt ist, dass er vorherige Vorgänge gab, und wie sie zu wiederholen wären. Wenn beispielsweise der zweite SaveChanges-Aufruf fehlschlägt, verfügt EF nicht mehr über die erforderlichen Informationen, um den ersten zu wiederholen.
Lösung: Aufrufausführungsstrategie manuell aufrufen
Die Lösung besteht darin, die Ausführungsstrategie manuell zu verwenden und ihr die gesamte auszuführende Logik zu übergeben, damit sie alles wiederholen kann, falls einer der Vorgänge fehlschlägt. Wenn eine von DbExecutionStrategy abgeleitete Ausführungsstrategie ausgeführt wird, wird sie die implizite Ausführungsstrategie anhalten, die in SaveChanges verwendet wird.
Beachten Sie, dass alle Kontexte innerhalb des Codeblocks erstellt werden sollten, für den ein Wiederholungsversuch ausgeführt werden soll. Dadurch wird sichergestellt, dass Sie jeden Wiederholungsversuch in einem sauberen Zustand beginnen.
var executionStrategy = new SqlAzureExecutionStrategy();
executionStrategy.Execute(
() =>
{
using (var db = new BloggingContext())
{
using (var trn = db.Database.BeginTransaction())
{
db.Blogs.Add(new Blog { Url = "http://msdn.com/data/ef" });
db.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/adonet" });
db.SaveChanges();
db.Blogs.Add(new Blog { Url = "http://twitter.com/efmagicunicorns" });
db.SaveChanges();
trn.Commit();
}
}
});