示例#1
0
        private static async Task <TResult> WithFuncAsyncCore <TTuple, TResult>(TaskFuncFactory <TTuple, TResult> factory, Action <TransientOperationOptions> setup) where TTuple : Template
        {
            var options = setup.ConfigureOptions();

            if (!options.EnableRecovery)
            {
                return(await factory.ExecuteMethodAsync().ContinueWithSuppressedContext());
            }
            DateTime         timestamp        = DateTime.UtcNow;
            TimeSpan         latency          = TimeSpan.Zero;
            TimeSpan         totalWaitTime    = TimeSpan.Zero;
            TimeSpan         lastWaitTime     = TimeSpan.Zero;
            bool             isTransientFault = false;
            bool             throwExceptions;
            List <Exception> aggregatedExceptions = new List <Exception>();
            TResult          result = default(TResult);

            for (int attempts = 0; ;)
            {
                bool     exceptionThrown = false;
                TimeSpan waitTime        = options.RetryStrategy(attempts);
                try
                {
                    if (latency > options.MaximumAllowedLatency)
                    {
                        throw new LatencyException(string.Format(CultureInfo.InvariantCulture, "The latency of the operation exceeded the allowed maximum value of {0} seconds. Actual latency was: {1} seconds.", options.MaximumAllowedLatency.TotalSeconds, latency.TotalSeconds));
                    }
                    return(await factory.ExecuteMethodAsync().ContinueWithSuppressedContext());
                }
                catch (Exception ex)
                {
                    try
                    {
                        lock (aggregatedExceptions) { aggregatedExceptions.Insert(0, ex); }
                        isTransientFault = options.DetectionStrategy(ex);
                        if (attempts >= options.RetryAttempts)
                        {
                            throw;
                        }
                        if (!isTransientFault)
                        {
                            throw;
                        }
                        lastWaitTime  = waitTime;
                        totalWaitTime = totalWaitTime.Add(waitTime);
                        attempts++;
                        await Task.Delay(waitTime).ContinueWithSuppressedContext();

                        latency = DateTime.UtcNow.Subtract(timestamp).Subtract(totalWaitTime);
                    }
                    catch (Exception)
                    {
                        throwExceptions = true;
                        exceptionThrown = true;
                        if (isTransientFault)
                        {
                            var evidence = new TransientFaultEvidence(attempts, lastWaitTime, totalWaitTime, latency, new MethodDescriptor(factory.DelegateInfo).ToString());
                            aggregatedExceptions.InsertTransientFaultException(evidence);
                            FaultCallback?.Invoke(evidence);
                        }
                        break;
                    }
                }
                finally
                {
                    if (exceptionThrown)
                    {
                        IDisposable disposable = result as IDisposable;
                        disposable?.Dispose();
                    }
                }
            }
            if (throwExceptions)
            {
                throw new AggregateException(aggregatedExceptions);
            }
            return(result);
        }
        private static void WithActionCore <TTuple>(ActionFactory <TTuple> factory, Action <TransientOperationOptions> setup = null) where TTuple : Template
        {
            var options = setup.ConfigureOptions();

            if (!options.EnableRecovery)
            {
                factory.ExecuteMethod();
                return;
            }
            DateTime         timestamp        = DateTime.UtcNow;
            TimeSpan         latency          = TimeSpan.Zero;
            TimeSpan         totalWaitTime    = TimeSpan.Zero;
            TimeSpan         lastWaitTime     = TimeSpan.Zero;
            bool             isTransientFault = false;
            bool             throwExceptions;
            List <Exception> aggregatedExceptions = new List <Exception>();

            for (int attempts = 0; ;)
            {
                TimeSpan waitTime = options.RetryStrategy(attempts);
                try
                {
                    if (latency > options.MaximumAllowedLatency)
                    {
                        throw new LatencyException(string.Format(CultureInfo.InvariantCulture, "The latency of the operation exceeded the allowed maximum value of {0} seconds. Actual latency was: {1} seconds.", options.MaximumAllowedLatency.TotalSeconds, latency.TotalSeconds));
                    }
                    factory.ExecuteMethod();
                    return;
                }
                catch (Exception ex)
                {
                    try
                    {
                        lock (aggregatedExceptions) { aggregatedExceptions.Insert(0, ex); }
                        isTransientFault = options.DetectionStrategy(ex);
                        if (attempts >= options.RetryAttempts)
                        {
                            throw;
                        }
                        if (!isTransientFault)
                        {
                            throw;
                        }
                        lastWaitTime  = waitTime;
                        totalWaitTime = totalWaitTime.Add(waitTime);
                        attempts++;
                        Sleep(waitTime);
                        latency = DateTime.UtcNow.Subtract(timestamp).Subtract(totalWaitTime);
                    }
                    catch (Exception)
                    {
                        throwExceptions = true;
                        if (isTransientFault)
                        {
                            var evidence = new TransientFaultEvidence(attempts, lastWaitTime, totalWaitTime, latency, new MethodDescriptor(factory.DelegateInfo).ToString());
                            aggregatedExceptions.InsertTransientFaultException(evidence);
                            FaultCallback?.Invoke(evidence);
                        }
                        break;
                    }
                }
            }
            if (throwExceptions)
            {
                throw new AggregateException(aggregatedExceptions);
            }
        }
        private static void InsertTransientFaultException(this IList <Exception> aggregatedExceptions, TransientFaultEvidence evidence)
        {
            TransientFaultException transientException = new TransientFaultException("The amount of retry attempts has been reached.", evidence);

            lock (aggregatedExceptions) { aggregatedExceptions.Insert(0, transientException); }
        }
示例#4
0
 /// <summary>
 /// Initializes a new instance of the <see cref="TransientFaultException"/> class.
 /// </summary>
 /// <param name="message">The message that describes the error.</param>
 /// <param name="innerException">The exception that is the cause of the current exception. If the innerException parameter is not a null reference, the current exception is raised in a catch block that handles the inner exception.</param>
 /// <param name="evidence">The evidence that provide details about the transient fault.</param>
 public TransientFaultException(string message, Exception innerException, TransientFaultEvidence evidence) : base(message, innerException)
 {
     Validator.ThrowIfNull(evidence, nameof(evidence));
     Evidence = evidence;
 }