예제 #1
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.
                                string response_intuit_tid_header = "";
                                //get intuit_tid header
                                for (int i = 0; i < errorResponse.Headers.Count; ++i)
                                {
                                    if (errorResponse.Headers.Keys[i] == "intuit_tid")
                                    {
                                        response_intuit_tid_header = errorResponse.Headers[i];
                                    }
                                }

                                // Log the error string to disk.
                                CoreHelper.GetRequestLogging(this.context).LogPlatformRequests(" Response Intuit_Tid header: " + response_intuit_tid_header + " Response Payload: " + 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);
                }
            }
        }
예제 #2
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();
                                            }
                                        }
                                        string response_intuit_tid_header = "";
                                        //get intuit_tid header
                                        for (int i = 0; i < errorResponse.Headers.Count; ++i)
                                        {
                                            if (errorResponse.Headers.Keys[i] == "intuit_tid")
                                            {
                                                response_intuit_tid_header = errorResponse.Headers[i];
                                            }
                                        }


                                        // Log the error string to disk.
                                        CoreHelper.GetRequestLogging(this.context).LogPlatformRequests(" Response Intuit_Tid header: " + response_intuit_tid_header + ", Response Payload: " + 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));
        }