Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Van toepassing op: .NET Framework
.NET
Standard
Als de ingebouwde logische providers voor opnieuw proberen niet aan uw behoeften voldoen, kunt u uw eigen aangepaste providers maken. Vervolgens kunt u deze providers toewijzen aan een SqlConnection of SqlCommand object om uw aangepaste logica toe te passen.
De ingebouwde providers zijn ontworpen rond drie interfaces die kunnen worden gebruikt om aangepaste providers te implementeren. Aangepaste providers voor nieuwe pogingen kunnen vervolgens op dezelfde manier worden gebruikt als interne providers voor opnieuw proberen op een SqlConnection of SqlCommand:
- SqlRetryIntervalBaseEnumerator: genereert een reeks tijdsintervallen.
- SqlRetryLogicBase: haalt het volgende tijdsinterval voor een bepaalde enumerator op als het aantal nieuwe pogingen niet is overschreden en aan een tijdelijke voorwaarde wordt voldaan.
- SqlRetryLogicBaseProvider: Hiermee past u logica voor opnieuw proberen toe op verbindings- en opdrachtbewerkingen.
Waarschuwing
Door een aangepaste logische provider voor opnieuw proberen te implementeren, bent u verantwoordelijk voor alle aspecten, waaronder gelijktijdigheid, prestaties en uitzonderingsbeheer.
Example
De implementatie in dit voorbeeld is zo eenvoudig mogelijk om stapsgewijze aanpassingen te demonstreren. Het bevat geen geavanceerde procedures zoals threadveiligheid, asynchroon en gelijktijdigheid. Voor een grondige analyse van een echte implementatie kunt u de vooraf gedefinieerde logica voor opnieuw proberen bestuderen in de GitHub-opslagplaats Microsoft.Data.SqlClient.
Configureerbare logicaklassen voor opnieuw proberen definiƫren:
- Enumerator: Definieer een vaste reeks tijdsintervallen en verleng het acceptabele tijdsbereik van twee minuten tot vier minuten.
public class CustomEnumerator : SqlRetryIntervalBaseEnumerator { // Set the maximum acceptable time to 4 minutes private readonly TimeSpan _maxValue = TimeSpan.FromMinutes(4); public CustomEnumerator(TimeSpan timeInterval, TimeSpan maxTime, TimeSpan minTime) : base(timeInterval, maxTime, minTime) {} // Return fixed time on each request protected override TimeSpan GetNextInterval() { return GapTimeInterval; } // Override the validate method with the new time range validation protected override void Validate(TimeSpan timeInterval, TimeSpan maxTimeInterval, TimeSpan minTimeInterval) { if (minTimeInterval < TimeSpan.Zero || minTimeInterval > _maxValue) { throw new ArgumentOutOfRangeException(nameof(minTimeInterval)); } if (maxTimeInterval < TimeSpan.Zero || maxTimeInterval > _maxValue) { throw new ArgumentOutOfRangeException(nameof(maxTimeInterval)); } if (timeInterval < TimeSpan.Zero || timeInterval > _maxValue) { throw new ArgumentOutOfRangeException(nameof(timeInterval)); } if (maxTimeInterval < minTimeInterval) { throw new ArgumentOutOfRangeException(nameof(minTimeInterval)); } } }- Logica voor opnieuw proberen: Implementeer logica voor opnieuw proberen op een opdracht die geen deel uitmaakt van een actieve transactie. Verlaag het aantal nieuwe pogingen van 60 tot 20.
public class CustomRetryLogic : SqlRetryLogicBase { // Maximum number of attempts private const int maxAttempts = 20; public CustomRetryLogic(int numberOfTries, SqlRetryIntervalBaseEnumerator enumerator, Predicate<Exception> transientPredicate) { if (!(numberOfTries > 0 && numberOfTries <= maxAttempts)) { // 'numberOfTries' should be between 1 and 20. throw new ArgumentOutOfRangeException(nameof(numberOfTries)); } // Assign parameters to the relevant properties NumberOfTries = numberOfTries; RetryIntervalEnumerator = enumerator; TransientPredicate = transientPredicate; Current = 0; } // Prepare this object for the next round public override void Reset() { Current = 0; RetryIntervalEnumerator.Reset(); } public override bool TryNextInterval(out TimeSpan intervalTime) { intervalTime = TimeSpan.Zero; // First try has occurred before starting the retry process. // Check if retry is still allowed bool result = Current < NumberOfTries - 1; if (result) { // Increase the number of attempts Current++; // It's okay if the RetryIntervalEnumerator gets to the last value before we've reached our maximum number of attempts. // MoveNext() will simply leave the enumerator on the final interval value and we will repeat that for the final attempts. RetryIntervalEnumerator.MoveNext(); // Receive the current time from enumerator intervalTime = RetryIntervalEnumerator.Current; } return result; } }-
Provider: Implementeert een provider voor opnieuw proberen die nieuwe pogingen uitvoert voor synchrone bewerkingen zonder een
Retryinggebeurtenis. Wordt toegevoegd TimeoutException aan de bestaande SqlException tijdelijke uitzonderingsfoutnummers.
public class CustomProvider : SqlRetryLogicBaseProvider { // Preserve the given retryLogic on creation public CustomProvider(SqlRetryLogicBase retryLogic) { RetryLogic = retryLogic; } public override TResult Execute<TResult>(object sender, Func<TResult> function) { // Create a list to save transient exceptions to report later if necessary IList<Exception> exceptions = new List<Exception>(); // Prepare it before reusing RetryLogic.Reset(); // Create an infinite loop to attempt the defined maximum number of tries do { try { // Try to invoke the function return function.Invoke(); } // Catch any type of exception for further investigation catch (Exception e) { // Ask the RetryLogic object if this exception is a transient error if (RetryLogic.TransientPredicate(e)) { // Add the exception to the list of exceptions we've retried on exceptions.Add(e); // Ask the RetryLogic for the next delay time before the next attempt to run the function if (RetryLogic.TryNextInterval(out TimeSpan gapTime)) { Console.WriteLine($"Wait for {gapTime} before next try"); // Wait before next attempt Thread.Sleep(gapTime); } else { // Number of attempts has exceeded the maximum number of tries throw new AggregateException("The number of retries has exceeded the maximum number of attempts.", exceptions); } } else { // If the exception wasn't a transient failure throw the original exception throw; } } } while (true); } public override Task<TResult> ExecuteAsync<TResult>(object sender, Func<Task<TResult>> function, CancellationToken cancellationToken = default) { throw new NotImplementedException(); } public override Task ExecuteAsync(object sender, Func<Task> function, CancellationToken cancellationToken = default) { throw new NotImplementedException(); } }Maak een exemplaar van een provider voor opnieuw proberen dat bestaat uit de gedefinieerde aangepaste typen:
public static SqlRetryLogicBaseProvider CreateCustomProvider(SqlRetryLogicOption options) { // 1. create an enumerator instance CustomEnumerator customEnumerator = new CustomEnumerator(options.DeltaTime, options.MaxTimeInterval, options.MinTimeInterval); // 2. Use the enumerator object to create a new RetryLogic instance CustomRetryLogic customRetryLogic = new CustomRetryLogic(5, customEnumerator, (e) => TransientErrorsCondition(e, options.TransientErrors)); // 3. Create a provider using the RetryLogic object CustomProvider customProvider = new CustomProvider(customRetryLogic); return customProvider; }- Met de volgende functie wordt een uitzondering geƫvalueerd met behulp van de opgegeven lijst met opnieuw te proberen uitzonderingen en de speciale TimeoutException uitzondering om te bepalen of deze opnieuw kan worden geprobeerd:
// Return true if the exception is a transient fault. private static bool TransientErrorsCondition(Exception e, IEnumerable<int> retriableConditions) { bool result = false; // Assess only SqlExceptions if (retriableConditions != null && e is SqlException ex) { foreach (SqlError item in ex.Errors) { // Check each error number to see if it is a retriable error number if (retriableConditions.Contains(item.Number)) { result = true; break; } } } // Other types of exceptions can also be assessed else if (e is TimeoutException) { result = true; } return result; }Gebruik de aangepaste logica voor opnieuw proberen:
- Definieer de logicaparameters voor opnieuw proberen:
// Define the retry logic parameters var options = new SqlRetryLogicOption() { // Tries 5 times before throwing an exception NumberOfTries = 5, // Preferred gap time to delay before retry DeltaTime = TimeSpan.FromSeconds(1), // Maximum gap time for each delay time before retry MaxTimeInterval = TimeSpan.FromSeconds(20), // SqlException retriable error numbers TransientErrors = new int[] { 4060, 1024, 1025} };- Een aangepaste provider voor opnieuw proberen maken:
// Create a custom retry logic provider SqlRetryLogicBaseProvider provider = CustomRetry.CreateCustomProvider(options);- Wijs de provider voor opnieuw proberen toe aan de SqlConnection.RetryLogicProvider of SqlCommand.RetryLogicProvider:
// Assumes that connection is a valid SqlConnection object // Set the retry logic provider on the connection instance connection.RetryLogicProvider = provider; // Establishing the connection will trigger retry if one of the given transient failure occurs. connection.Open();