/// <summary>Executes a function and applies retry logic, if enabled.</summary> public override async Task <TResult> ExecuteAsync <TResult>(object sender, Func <Task <TResult> > function, CancellationToken cancellationToken = default) { if (function == null) { throw SqlReliabilityUtil.ArgumentNull(nameof(function)); } SqlRetryLogicBase retryLogic = null; var exceptions = new List <Exception>(); retry: try { TResult result = await function.Invoke(); RetryLogicPoolAdd(retryLogic); return(result); } catch (Exception e) { if (RetryLogic.RetryCondition(sender) && RetryLogic.TransientPredicate(e)) { retryLogic = retryLogic ?? GetRetryLogic(); SqlClientEventSource.Log.TryTraceEvent("<sc.{0}.ExecuteAsync<TResult>|INFO> Found an action eligible for the retry policy (retried attempts = {1}).", TypeName, retryLogic.Current); exceptions.Add(e); if (retryLogic.TryNextInterval(out TimeSpan intervalTime)) { // The retrying event raises on each retry. ApplyRetryingEvent(sender, retryLogic, intervalTime, exceptions, e); await Task.Delay(intervalTime, cancellationToken); goto retry; } else { throw CreateException(exceptions, retryLogic); } } else { RetryLogicPoolAdd(retryLogic); throw; } } }
/// <summary>Executes a function and applies retry logic, if enabled.</summary> public override TResult Execute <TResult>(object sender, Func <TResult> function) { if (function == null) { throw new ArgumentNullException(nameof(function)); } SqlRetryLogicBase retryLogic = null; var exceptions = new List <Exception>(); retry: try { TResult result = function.Invoke(); RetryLogicPoolAdd(retryLogic); return(result); } catch (Exception e) { if (enableRetryLogic && RetryLogic.RetryCondition(sender) && RetryLogic.TransientPredicate(e)) { retryLogic = retryLogic ?? GetRetryLogic(); SqlClientEventSource.Log.TryTraceEvent("<sc.{0}.Execute<TResult>|INFO> Found an action eligible for the retry policy (retried attempts = {1}).", TypeName, retryLogic.Current); exceptions.Add(e); if (retryLogic.TryNextInterval(out TimeSpan intervalTime)) { // The retrying event raises on each retry. ApplyRetryingEvent(sender, retryLogic, intervalTime, exceptions, e); Thread.Sleep(intervalTime); goto retry; } else { throw CreateException(exceptions, retryLogic); } } else { RetryLogicPoolAdd(retryLogic); throw; } } }
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); }