/// <summary> /// Attempt to execute the supplied function. /// </summary> /// <param name="numberOfAttempts"> /// The number of attempts to try /// </param> /// <param name="interval"> /// The amount of time to wait inbetween attempts /// </param> /// <param name="functionToAttempt"> /// The function to try and execute /// </param> /// <param name="handleExceptions"> /// Whether or not to handle exceptions that get thrown as part of /// executing the supplied function. /// </param> /// <returns> /// An OperationResult that denotes whether or not the function succeeded. /// If the function succeeded then OperationResult.Succeeded is returned. /// If the function failed then a failure OperationResult is returned with /// details of the failuer and any thrown exceptions (if handleExceptions was true) /// </returns> /// <exception cref="System.ArgumentException"> /// Thrown if /// numberOfAttempts is less than 1 /// interval is less than 1 millisecond /// </exception> /// <exception cref="System.ArgumentNullException"> /// Thrown if /// functionToAttempt is null /// </exception> public static OperationResult Attempt( Func <bool> functionToAttempt, int numberOfAttempts, TimeSpan interval, RetryExceptionBehaviour exceptionBehaviour) { #region Input validation Insist.IsAtLeast(numberOfAttempts, 1, "numberOfAttempts"); Insist.IsAtLeast(interval, TimeSpan.FromMilliseconds(1), "interval"); Insist.IsNotNull(functionToAttempt, "functionToAttempt"); Insist.IsDefined <RetryExceptionBehaviour>(exceptionBehaviour, "exceptionBehaviour"); #endregion int currentAttempts = 0; List <Exception> thrownExceptions = new List <Exception>(); int numberOfThrownExceptions = 0; bool usingInfiniteAttempts = numberOfAttempts == INFINITE_ATTEMPTS; while (currentAttempts < numberOfAttempts) { bool success = false; try { success = functionToAttempt(); } catch (Exception e) { if (exceptionBehaviour == RetryExceptionBehaviour.DoNotHandle) { throw; } else if (exceptionBehaviour == RetryExceptionBehaviour.HandleAndCollate) { //Record the exception so that we can return information //about it later on. thrownExceptions.Add(e); numberOfThrownExceptions++; } else if (exceptionBehaviour == RetryExceptionBehaviour.HandleOnly) { numberOfThrownExceptions++; } else { throw new InvalidOperationException(string.Format("Unknown RetryExceptionBehaviour '{0}'", exceptionBehaviour)); } } if (success) { return(OperationResult.Succeeded); } if (!usingInfiniteAttempts) //If we're using an infinite number of attempts then //we don't want to make any progress regards number of //attempts. Just keep looping until the attempt succeeds. { currentAttempts++; } Thread.Sleep(interval); } //If we get to this point then all attempts have failed. List <string> errorMessages = new List <string>(); errorMessages.Add(string.Format("The function was not successfull after {0} attempts", numberOfAttempts)); if (numberOfThrownExceptions > 0) { if (exceptionBehaviour == RetryExceptionBehaviour.HandleAndCollate) { errorMessages.AddRange(thrownExceptions.Select(ex => ex.AllMessages())); } else if (exceptionBehaviour == RetryExceptionBehaviour.HandleOnly) { errorMessages.Add(string.Format(string.Format("A total of '{0}' exceptions were thrown during the attempt", numberOfThrownExceptions))); } } return(new OperationResult(errorMessages)); }
/// <summary> /// Attempt to execute the supplied function. /// </summary> /// <param name="numberOfAttempts"> /// The number of attempts to try /// </param> /// <param name="interval"> /// The amount of time to wait inbetween attempts /// </param> /// <param name="functionToAttempt"> /// The function to try and execute /// </param> /// <param name="handleExceptions"> /// Whether or not to handle exceptions that get thrown as part of /// executing the supplied function. /// </param> /// <returns> /// An OperationResult that denotes whether or not the function succeeded. /// If the function succeeded then OperationResult.Succeeded is returned. /// If the function failed then a failure OperationResult is returned with /// details of the failuer and any thrown exceptions (if handleExceptions was true) /// </returns> /// <exception cref="System.ArgumentException"> /// Thrown if /// numberOfAttempts is less than 1 /// interval is less than 1 millisecond /// </exception> /// <exception cref="System.ArgumentNullException"> /// Thrown if /// functionToAttempt is null /// </exception> public static OperationResult Attempt( Func<bool> functionToAttempt, int numberOfAttempts, TimeSpan interval, RetryExceptionBehaviour exceptionBehaviour) { #region Input validation Insist.IsAtLeast(numberOfAttempts, 1, "numberOfAttempts"); Insist.IsAtLeast(interval, TimeSpan.FromMilliseconds(1), "interval"); Insist.IsNotNull(functionToAttempt, "functionToAttempt"); Insist.IsDefined<RetryExceptionBehaviour>(exceptionBehaviour, "exceptionBehaviour"); #endregion int currentAttempts = 0; List<Exception> thrownExceptions = new List<Exception>(); int numberOfThrownExceptions = 0; bool usingInfiniteAttempts = numberOfAttempts == INFINITE_ATTEMPTS; while (currentAttempts < numberOfAttempts) { bool success = false; try { success = functionToAttempt(); } catch (Exception e) { if (exceptionBehaviour == RetryExceptionBehaviour.DoNotHandle) { throw; } else if( exceptionBehaviour == RetryExceptionBehaviour.HandleAndCollate) { //Record the exception so that we can return information //about it later on. thrownExceptions.Add(e); numberOfThrownExceptions++; } else if (exceptionBehaviour == RetryExceptionBehaviour.HandleOnly) { numberOfThrownExceptions++; } else { throw new InvalidOperationException(string.Format("Unknown RetryExceptionBehaviour '{0}'", exceptionBehaviour)); } } if (success) { return OperationResult.Succeeded; } if (!usingInfiniteAttempts) //If we're using an infinite number of attempts then //we don't want to make any progress regards number of //attempts. Just keep looping until the attempt succeeds. { currentAttempts++; } Thread.Sleep(interval); } //If we get to this point then all attempts have failed. List<string> errorMessages = new List<string>(); errorMessages.Add(string.Format("The function was not successfull after {0} attempts", numberOfAttempts)); if (numberOfThrownExceptions > 0) { if (exceptionBehaviour == RetryExceptionBehaviour.HandleAndCollate) { errorMessages.AddRange(thrownExceptions.Select(ex => ex.AllMessages())); } else if(exceptionBehaviour == RetryExceptionBehaviour.HandleOnly) { errorMessages.Add(string.Format(string.Format("A total of '{0}' exceptions were thrown during the attempt", numberOfThrownExceptions))); } } return new OperationResult(errorMessages); }