Example #1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="IntuitRetryingEventArgs"/> class.
        /// </summary>
        /// <param name="currentRetryCount">The current retry attempt count.</param>
        /// <param name="delay">The delay indicating how long the current thread will be suspended for before the next iteration will be invoked.</param>
        /// <param name="lastException">The exception which caused the retry conditions to occur.</param>
        public IntuitRetryingEventArgs(int currentRetryCount, TimeSpan delay, System.Exception lastException)
        {
            IntuitRetryHelper.IsArgumentNull(lastException, "lastException");

            this.CurrentRetryCount = currentRetryCount;
            this.Delay             = delay;
            this.LastException     = lastException;
        }
Example #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="IntuitRetryPolicy"/> class.
        /// </summary>
        /// <param name="retryCount">The number of retry attempts.</param>
        /// <param name="retryInterval">The time interval between retries.</param>
        public IntuitRetryPolicy(int retryCount, TimeSpan retryInterval)
        {
            IntuitRetryHelper.ArgumentNotNegativeValue(retryCount, "retryCount");
            IntuitRetryHelper.ArgumentNotNegativeValue(retryInterval.Ticks, "retryInterval");

            this.retryCount    = retryCount;
            this.retryInterval = retryInterval;
            this.shouldRetry   = this.GetShouldFixedRetry();
        }
Example #3
0
        /// <summary>
        /// Initializes a new instance of the <see cref="IntuitRetryPolicy"/> class.
        /// </summary>
        /// <param name="retryCount">The number of retry attempts.</param>
        /// <param name="initialInterval">The initial interval that will apply for the first retry.</param>
        /// <param name="increment">The incremental time value that will be used for calculating the progressive delay between retries.</param>
        public IntuitRetryPolicy(int retryCount, TimeSpan initialInterval, TimeSpan increment)
        {
            IntuitRetryHelper.ArgumentNotNegativeValue(retryCount, "retryCount");
            IntuitRetryHelper.ArgumentNotNegativeValue(initialInterval.Ticks, "initialInterval");
            IntuitRetryHelper.ArgumentNotNegativeValue(increment.Ticks, "increment");

            this.retryCount      = retryCount;
            this.initialInterval = initialInterval;
            this.increment       = increment;
            this.shouldRetry     = this.GetShouldIncrementalRetry();
        }
Example #4
0
        /// <summary>
        /// Repetitively executes the specified asynchronous action while it satisfies the current retry policy.
        /// </summary>
        /// <param name="beginAction">The begin method of the async pattern.</param>
        /// <param name="endAction">The end method of the async pattern.</param>
        /// <param name="successHandler">The action to perform when the async operation is done.</param>
        /// <param name="faultHandler">The fault handler delegate that will be triggered if the operation cannot be successfully invoked despite retry attempts.</param>
        public void ExecuteAction(Action <AsyncCallback> beginAction, Action <IAsyncResult> endAction, Action successHandler, Action <Exception> faultHandler)
        {
            IntuitRetryHelper.IsArgumentNull(beginAction, "beginAction");
            IntuitRetryHelper.IsArgumentNull(endAction, "endAction");
            IntuitRetryHelper.IsArgumentNull(successHandler, "successHandler");
            IntuitRetryHelper.IsArgumentNull(faultHandler, "faultHandler");

            this.ExecuteAction <object>(
                beginAction,
                ar => { endAction(ar); return(null); },
                _ => successHandler(),
                faultHandler);
        }
Example #5
0
        /// <summary>
        /// Initializes a new instance of the <see cref="IntuitRetryPolicy"/> class.
        /// </summary>
        /// <param name="retryCount">The maximum number of retry attempts.</param>
        /// <param name="minBackoff">The minimum back-off time</param>
        /// <param name="maxBackoff">The maximum back-off time.</param>
        /// <param name="deltaBackoff">The value which will be used to calculate a random delta in the exponential delay between retries.</param>
        public IntuitRetryPolicy(int retryCount, TimeSpan minBackoff, TimeSpan maxBackoff, TimeSpan deltaBackoff)
        {
            IntuitRetryHelper.ArgumentNotNegativeValue(retryCount, "retryCount");
            IntuitRetryHelper.ArgumentNotNegativeValue(minBackoff.Ticks, "minBackoff");
            IntuitRetryHelper.ArgumentNotNegativeValue(maxBackoff.Ticks, "maxBackoff");
            IntuitRetryHelper.ArgumentNotNegativeValue(deltaBackoff.Ticks, "deltaBackoff");
            IntuitRetryHelper.ArgumentNotGreaterThan(minBackoff.TotalMilliseconds, maxBackoff.TotalMilliseconds, "minBackoff");

            this.retryCount   = retryCount;
            this.minBackOff   = minBackoff;
            this.maxBackOff   = maxBackoff;
            this.deltaBackOff = deltaBackoff;
            this.shouldRetry  = this.GetShouldExponentialBackOffRetry();
        }
Example #6
0
        /// <summary>
        /// Repetitively executes the specified action while it satisfies the current retry policy.
        /// </summary>
        /// <typeparam name="TResult">The type of result expected from the executable action.</typeparam>
        /// <param name="func">A delegate representing the executable action which returns the result of type R.</param>
        /// <returns>The result from the action.</returns>
        private TResult ExecuteAction <TResult>(Func <TResult> func)
        {
            IntuitRetryHelper.IsArgumentNull(func, "func");

            int       retryCount = 1;
            TimeSpan  delay      = TimeSpan.Zero;
            Exception lastError;

            while (true)
            {
                lastError = null;

                try
                {
                    return(func());
                }
                catch (RetryExceededException retryExceededException)
                {
                    // The user code can throw a RetryLimitExceededException to force the exit from the retry loop.
                    // The RetryLimitExceeded exception can have an inner exception attached to it. This is the exception
                    // which we will have to throw up the stack so that callers can handle it.
                    if (retryExceededException.InnerException != null)
                    {
                        throw retryExceededException.InnerException;
                    }
                    else
                    {
                        return(default(TResult));
                    }
                }
                catch (Exception ex)
                {
                    lastError = ex;

                    if (!IsTransient(lastError) || ((this.ExtendedRetryException != null) && this.ExtendedRetryException.IsRetryException(ex)))
                    {
                        throw;
                    }

                    if (!this.shouldRetry(retryCount++, lastError, out delay))
                    {
                        WebException webException = ex as WebException;


                        string errorString = string.Empty;

                        if (webException != null)
                        {
                            // If not null then check the response property of the webException object.
                            if (webException.Response != null)
                            {
                                // There is a response from the Ids server. Cast it to HttpWebResponse.
                                HttpWebResponse errorResponse = (HttpWebResponse)webException.Response;

                                // Get the status code description of the error response.
                                string statusCodeDescription = errorResponse.StatusCode.ToString();

                                // Get the status code of the error response.
                                int statusCode = (int)errorResponse.StatusCode;


                                ICompressor responseCompressor = CoreHelper.GetCompressor(this.context, false);
                                if (!string.IsNullOrWhiteSpace(errorResponse.ContentEncoding) && responseCompressor != null)
                                {
                                    using (var responseStream = errorResponse.GetResponseStream()) //Check for decompressing
                                    {
                                        using (var decompressedStream = responseCompressor.Decompress(responseStream))
                                        {
                                            // Get the response stream.
                                            StreamReader reader = new StreamReader(decompressedStream);
                                            //StreamReader reader = new StreamReader(responseStream);

                                            // Read the Stream
                                            errorString = reader.ReadToEnd();
                                            // Close reader
                                            reader.Close();
                                        }
                                    }
                                }
                                else
                                {
                                    using (Stream responseStream = errorResponse.GetResponseStream())
                                    {
                                        // Get the response stream.
                                        StreamReader reader = new StreamReader(responseStream);

                                        // Read the Stream
                                        errorString = reader.ReadToEnd();
                                        // Close reader
                                        reader.Close();
                                    }
                                }

                                // Log the error string to disk.
                                CoreHelper.GetRequestLogging(this.context).LogPlatformRequests(errorString, false);
                            }
                        }

                        Core.Rest.FaultHandler fault        = new Core.Rest.FaultHandler(this.context);
                        IdsException           idsException = fault.ParseErrorResponseAndPrepareException(errorString);



                        if (idsException != null)
                        {
                            throw new RetryExceededException(webException.Message, webException.Status.ToString(), webException.Source, idsException);
                        }
                        else if (webException != null)
                        {
                            throw new RetryExceededException(webException.Message, webException.Status.ToString(), webException.Source, webException);
                        }

                        throw new RetryExceededException(ex.Message, ex);
                    }
                }

                // Perform an extra check in the delay interval. Should prevent from accidentally ending up with the value of -1 that will block a thread indefinitely.
                // In addition, any other negative numbers will cause an ArgumentOutOfRangeException fault that will be thrown by Thread.Sleep.
                if (delay.TotalMilliseconds < 0)
                {
                    delay = TimeSpan.Zero;
                }

                this.OnRetrying(retryCount - 1, lastError, delay);

                if (retryCount > 2 && delay > TimeSpan.Zero)
                {
                    Thread.Sleep(delay);
                }
            }
        }
Example #7
0
        public void ExecuteAction <TResult>(Action <AsyncCallback> beginAction, Func <IAsyncResult, TResult> endAction, Action <TResult> successHandler, Action <Exception> faultHandler)
        {
            IntuitRetryHelper.IsArgumentNull(beginAction, "beginAction");
            IntuitRetryHelper.IsArgumentNull(endAction, "endAction");
            IntuitRetryHelper.IsArgumentNull(successHandler, "successHandler");
            IntuitRetryHelper.IsArgumentNull(faultHandler, "faultHandler");

            int                 retryCount       = 0;
            AsyncCallback       endInvoke        = null;
            Func <Action, bool> executeWithRetry = null;

            // Configure a custom callback delegate that invokes the end operation and the success handler if the operation succeedes
            endInvoke =
                ar =>
            {
                var result = default(TResult);

                if (executeWithRetry(() => result = endAction(ar)))
                {
                    successHandler(result);
                }
            };

            // Utility delegate to invoke an action and implement the core retry logic
            // If the action succeeds (i.e. does not throw an exception) it returns true.
            // If the action throws, it analizes it for retries. If a retry is required, it restarts the async operation; otherwise, it invokes the fault handler.
            executeWithRetry =
                a =>
            {
                try
                {
                    // Invoke the callback delegate which can throw an exception if the main async operation has completed with a fault.
                    a();
                    return(true);
                }
                catch (Exception ex)
                {
                    // Capture the original exception for analysis.
                    var lastError = ex;

                    // Handling of RetryLimitExceededException needs to be done separately. This exception type indicates the application's intent to exit from the retry loop.
                    if (lastError is RetryExceededException)
                    {
                        if (lastError.InnerException != null)
                        {
                            faultHandler(lastError.InnerException);
                            return(false);
                        }
                        else
                        {
                            faultHandler(lastError);
                            return(false);
                        }
                    }
                    else
                    {
                        var delay = TimeSpan.Zero;

                        // Check if we should continue retrying on this exception. If not, invoke the fault handler so that user code can take control.
                        if (!IsTransient(lastError) || ((this.ExtendedRetryException != null) && this.ExtendedRetryException.IsRetryException(ex)))
                        {
                            faultHandler(lastError);
                            return(false);
                        }
                        else
                        {
                            if (delay.TotalMilliseconds < 0)
                            {
                                delay = TimeSpan.Zero;
                            }

                            retryCount = retryCount + 1;
                            if (!this.shouldRetry(retryCount, lastError, out delay))
                            {
                                WebException webException = ex as WebException;



                                string errorString = string.Empty;
                                if (webException != null)
                                {
                                    // If not null then check the response property of the webException object.
                                    if (webException.Response != null)
                                    {
                                        // There is a response from the Ids server. Cast it to HttpWebResponse.
                                        HttpWebResponse errorResponse = (HttpWebResponse)webException.Response;

                                        // Get the status code description of the error response.
                                        string statusCodeDescription = errorResponse.StatusCode.ToString();

                                        // Get the status code of the error response.
                                        int statusCode = (int)errorResponse.StatusCode;


                                        ICompressor responseCompressor = CoreHelper.GetCompressor(this.context, false);
                                        if (!string.IsNullOrWhiteSpace(errorResponse.ContentEncoding) && responseCompressor != null)
                                        {
                                            using (var responseStream = errorResponse.GetResponseStream()) //Check for decompressing
                                            {
                                                using (var decompressedStream = responseCompressor.Decompress(responseStream))
                                                {
                                                    // Get the response stream.
                                                    StreamReader reader = new StreamReader(decompressedStream);
                                                    //StreamReader reader = new StreamReader(responseStream);

                                                    // Read the Stream
                                                    errorString = reader.ReadToEnd();
                                                    // Close reader
                                                    reader.Close();
                                                }
                                            }
                                        }
                                        else
                                        {
                                            using (Stream responseStream = errorResponse.GetResponseStream())
                                            {
                                                // Get the response stream.
                                                StreamReader reader = new StreamReader(responseStream);

                                                // Read the Stream
                                                errorString = reader.ReadToEnd();
                                                // Close reader
                                                reader.Close();
                                            }
                                        }

                                        // Log the error string to disk.
                                        CoreHelper.GetRequestLogging(this.context).LogPlatformRequests(errorString, false);
                                    }
                                }

                                Core.Rest.FaultHandler fault        = new Core.Rest.FaultHandler(this.context);
                                IdsException           idsException = fault.ParseErrorResponseAndPrepareException(errorString);



                                if (idsException != null)
                                {
                                    faultHandler(new RetryExceededException(webException.Message, webException.Status.ToString(), webException.Source, idsException));
                                    return(false);
                                }
                                else if (webException != null)
                                {
                                    faultHandler(new RetryExceededException(webException.Message, webException.Status.ToString(), webException.Source, webException));
                                    return(false);
                                }

                                faultHandler(new RetryExceededException(ex.Message, ex));
                                return(false);
                            }

                            // Notify the respective subscribers about this exception.
                            this.OnRetrying(retryCount, lastError, delay);

                            // Sleep for the defined interval before repetitively executing the main async operation.
                            if (retryCount > 2 && delay > TimeSpan.Zero)
                            {
                                Thread.Sleep(delay);
                            }

                            executeWithRetry(() => beginAction(endInvoke));
                        }
                    }

                    return(false);
                }
            };

            // Invoke the the main async operation for the first time which should return control to the caller immediately.
            executeWithRetry(() => beginAction(endInvoke));
        }
Example #8
0
        /// <summary>
        /// Repetitively executes the specified action while it satisfies the current retry policy.
        /// </summary>
        /// <param name="action">A delegate representing the executable action which doesn't return any results.</param>
        public void ExecuteAction(Action action)
        {
            IntuitRetryHelper.IsArgumentNull(action, "action");

            this.ExecuteAction(() => { action(); return(default(object)); });
        }
        /// <summary>
        /// Repetitively executes the specified action while it satisfies the current retry policy.
        /// </summary>
        /// <typeparam name="TResult">The type of result expected from the executable action.</typeparam>
        /// <param name="func">A delegate representing the executable action which returns the result of type R.</param>
        /// <returns>The result from the action.</returns>
        private TResult ExecuteAction <TResult>(Func <TResult> func)
        {
            IntuitRetryHelper.IsArgumentNull(func, "func");

            int       retryCount = 1;
            TimeSpan  delay      = TimeSpan.Zero;
            Exception lastError;

            while (true)
            {
                lastError = null;

                try
                {
                    return(func());
                }
                catch (RetryExceededException retryExceededException)
                {
                    // The user code can throw a RetryLimitExceededException to force the exit from the retry loop.
                    // The RetryLimitExceeded exception can have an inner exception attached to it. This is the exception
                    // which we will have to throw up the stack so that callers can handle it.
                    if (retryExceededException.InnerException != null)
                    {
                        throw retryExceededException.InnerException;
                    }
                    else
                    {
                        return(default(TResult));
                    }
                }
                catch (Exception ex)
                {
                    lastError = ex;

                    if (!IsTransient(lastError) || ((this.ExtendedRetryException != null) && this.ExtendedRetryException.IsRetryException(ex)))
                    {
                        throw;
                    }

                    if (!this.shouldRetry(retryCount++, lastError, out delay))
                    {
                        WebException webException = ex as WebException;
                        if (webException != null)
                        {
                            throw new RetryExceededException(webException.Message, webException.Status.ToString(), webException.Source, webException);
                        }

                        throw new RetryExceededException(ex.Message, ex);
                    }
                }

                // Perform an extra check in the delay interval. Should prevent from accidentally ending up with the value of -1 that will block a thread indefinitely.
                // In addition, any other negative numbers will cause an ArgumentOutOfRangeException fault that will be thrown by Thread.Sleep.
                if (delay.TotalMilliseconds < 0)
                {
                    delay = TimeSpan.Zero;
                }

                this.OnRetrying(retryCount - 1, lastError, delay);

                if (retryCount > 2 && delay > TimeSpan.Zero)
                {
                    Thread.Sleep(delay);
                }
            }
        }
        public void ExecuteAction <TResult>(Action <AsyncCallback> beginAction, Func <IAsyncResult, TResult> endAction, Action <TResult> successHandler, Action <Exception> faultHandler)
        {
            IntuitRetryHelper.IsArgumentNull(beginAction, "beginAction");
            IntuitRetryHelper.IsArgumentNull(endAction, "endAction");
            IntuitRetryHelper.IsArgumentNull(successHandler, "successHandler");
            IntuitRetryHelper.IsArgumentNull(faultHandler, "faultHandler");

            int                 retryCount       = 0;
            AsyncCallback       endInvoke        = null;
            Func <Action, bool> executeWithRetry = null;

            // Configure a custom callback delegate that invokes the end operation and the success handler if the operation succeedes
            endInvoke =
                ar =>
            {
                var result = default(TResult);

                if (executeWithRetry(() => result = endAction(ar)))
                {
                    successHandler(result);
                }
            };

            // Utility delegate to invoke an action and implement the core retry logic
            // If the action succeeds (i.e. does not throw an exception) it returns true.
            // If the action throws, it analizes it for retries. If a retry is required, it restarts the async operation; otherwise, it invokes the fault handler.
            executeWithRetry =
                a =>
            {
                try
                {
                    // Invoke the callback delegate which can throw an exception if the main async operation has completed with a fault.
                    a();
                    return(true);
                }
                catch (Exception ex)
                {
                    // Capture the original exception for analysis.
                    var lastError = ex;

                    // Handling of RetryLimitExceededException needs to be done separately. This exception type indicates the application's intent to exit from the retry loop.
                    if (lastError is RetryExceededException)
                    {
                        if (lastError.InnerException != null)
                        {
                            faultHandler(lastError.InnerException);
                            return(false);
                        }
                        else
                        {
                            faultHandler(lastError);
                            return(false);
                        }
                    }
                    else
                    {
                        var delay = TimeSpan.Zero;

                        // Check if we should continue retrying on this exception. If not, invoke the fault handler so that user code can take control.
                        if (!IsTransient(lastError) || ((this.ExtendedRetryException != null) && this.ExtendedRetryException.IsRetryException(ex)))
                        {
                            faultHandler(lastError);
                            return(false);
                        }
                        else
                        {
                            if (delay.TotalMilliseconds < 0)
                            {
                                delay = TimeSpan.Zero;
                            }

                            retryCount = retryCount + 1;
                            if (!this.shouldRetry(retryCount, lastError, out delay))
                            {
                                WebException webException = ex as WebException;
                                if (webException != null)
                                {
                                    faultHandler(new RetryExceededException(webException.Message, webException.Status.ToString(), webException.Source, webException));
                                    return(false);
                                }

                                faultHandler(new RetryExceededException(ex.Message, ex));
                                return(false);
                            }

                            // Notify the respective subscribers about this exception.
                            this.OnRetrying(retryCount, lastError, delay);

                            // Sleep for the defined interval before repetitively executing the main async operation.
                            if (retryCount > 2 && delay > TimeSpan.Zero)
                            {
                                Thread.Sleep(delay);
                            }

                            executeWithRetry(() => beginAction(endInvoke));
                        }
                    }

                    return(false);
                }
            };

            // Invoke the the main async operation for the first time which should return control to the caller immediately.
            executeWithRetry(() => beginAction(endInvoke));
        }