/// <summary>
        /// Profile and time measure the specified <paramref name="function"/> delegate.
        /// </summary>
        /// <typeparam name="T1">The type of the first parameter of the <paramref name="function" /> delegate.</typeparam>
        /// <typeparam name="T2">The type of the second parameter of the <paramref name="function" /> delegate.</typeparam>
        /// <typeparam name="T3">The type of the third parameter of the <paramref name="function" /> delegate.</typeparam>
        /// <typeparam name="T4">The type of the fourth parameter of the <paramref name="function" /> delegate.</typeparam>
        /// <typeparam name="T5">The type of the fifth parameter of the <paramref name="function" /> delegate.</typeparam>
        /// <typeparam name="T6">The type of the sixth parameter of the <paramref name="function" /> delegate.</typeparam>
        /// <typeparam name="T7">The type of the seventh parameter of the <paramref name="function" /> delegate.</typeparam>
        /// <typeparam name="T8">The type of the eighth parameter of the <paramref name="function" /> delegate.</typeparam>
        /// <typeparam name="T9">The type of the ninth parameter of the <paramref name="function" /> delegate.</typeparam>
        /// <typeparam name="T10">The type of the tenth parameter of the <paramref name="function" /> delegate.</typeparam>
        /// <typeparam name="TResult">The type of the return value of the <paramref name="function"/> delegate.</typeparam>
        /// <param name="function">The function delegate to time measure.</param>
        /// <param name="arg1">The first parameter of the <paramref name="function" /> delegate.</param>
        /// <param name="arg2">The second parameter of the <paramref name="function" /> delegate.</param>
        /// <param name="arg3">The third parameter of the <paramref name="function" /> delegate.</param>
        /// <param name="arg4">The fourth parameter of the <paramref name="function" /> delegate.</param>
        /// <param name="arg5">The fifth parameter of the <paramref name="function" /> delegate.</param>
        /// <param name="arg6">The sixth parameter of the <paramref name="function" /> delegate.</param>
        /// <param name="arg7">The seventh parameter of the <paramref name="function" /> delegate.</param>
        /// <param name="arg8">The eighth parameter of the <paramref name="function" /> delegate.</param>
        /// <param name="arg9">The ninth parameter of the <paramref name="function" /> delegate .</param>
        /// <param name="arg10">The tenth parameter of the <paramref name="function" /> delegate.</param>
        /// <param name="setup">The <see cref="TimeMeasureOptions"/> which need to be configured.</param>
        /// <returns>A <see cref="TimeMeasureProfiler{TResult}"/> with the result of the time measuring and the encapsulated <paramref name="function"/> delegate.</returns>
        public static Task <TimeMeasureProfiler <TResult> > WithFuncAsync <T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult>(Func <T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, Task <TResult> > function, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, Action <TimeMeasureOptions> setup = null)
        {
            Validator.ThrowIfNull(function, nameof(function));
            var factory = TaskFuncFactory.Create(function, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);

            return(WithFunctionAsyncCore(factory, setup));
        }
        /// <summary>
        /// Profile and time measure the specified <paramref name="function"/> delegate.
        /// </summary>
        /// <typeparam name="T1">The type of the first parameter of the <paramref name="function" /> delegate.</typeparam>
        /// <typeparam name="T2">The type of the second parameter of the <paramref name="function" /> delegate.</typeparam>
        /// <typeparam name="T3">The type of the third parameter of the <paramref name="function" /> delegate.</typeparam>
        /// <typeparam name="TResult">The type of the return value of the <paramref name="function"/> delegate.</typeparam>
        /// <param name="function">The function delegate to time measure.</param>
        /// <param name="arg1">The first parameter of the <paramref name="function" /> delegate.</param>
        /// <param name="arg2">The second parameter of the <paramref name="function" /> delegate.</param>
        /// <param name="arg3">The third parameter of the <paramref name="function" /> delegate.</param>
        /// <param name="setup">The <see cref="TimeMeasureOptions"/> which need to be configured.</param>
        /// <returns>A <see cref="TimeMeasureProfiler{TResult}"/> with the result of the time measuring and the encapsulated <paramref name="function"/> delegate.</returns>
        public static Task <TimeMeasureProfiler <TResult> > WithFuncAsync <T1, T2, T3, TResult>(Func <T1, T2, T3, Task <TResult> > function, T1 arg1, T2 arg2, T3 arg3, Action <TimeMeasureOptions> setup = null)
        {
            Validator.ThrowIfNull(function, nameof(function));
            var factory = TaskFuncFactory.Create(function, arg1, arg2, arg3);

            return(WithFunctionAsyncCore(factory, setup));
        }
        private static async Task <TimeMeasureProfiler <TResult> > WithFunctionAsyncCore <TTuple, TResult>(TaskFuncFactory <TTuple, TResult> factory, Action <TimeMeasureOptions> setup) where TTuple : Template
        {
            var options    = setup.ConfigureOptions();
            var descriptor = options.MethodDescriptor?.Invoke() ?? new MethodDescriptor(factory.DelegateInfo);
            var profiler   = new TimeMeasureProfiler <TResult>()
            {
                Member = descriptor.ToString(),
                Data   = descriptor.MergeParameters(options.RuntimeParameters ?? factory.GenericArguments.ToArray())
            };

            await PerformTimeMeasuringAsync(profiler, options, async p => p.Result = await factory.ExecuteMethodAsync().ContinueWithSuppressedContext()).ContinueWithSuppressedContext();

            return(profiler);
        }
Exemple #4
0
        /// <summary>
        /// Repetitively executes the specified <paramref name="faultSensitiveMethod"/> until the operation is successful, the amount of retry attempts has been reached, or a failed operation is not considered related to transient fault condition.
        /// </summary>
        /// <typeparam name="T1">The type of the first parameter of the function delegate <paramref name="faultSensitiveMethod"/>.</typeparam>
        /// <typeparam name="T2">The type of the second parameter of the function delegate <paramref name="faultSensitiveMethod"/>.</typeparam>
        /// <typeparam name="T3">The type of the third parameter of the function delegate <paramref name="faultSensitiveMethod"/>.</typeparam>
        /// <typeparam name="T4">The type of the fourth parameter of the function delegate <paramref name="faultSensitiveMethod"/>.</typeparam>
        /// <typeparam name="TResult">The type of the return value of the function delegate <paramref name="faultSensitiveMethod"/>.</typeparam>
        /// <param name="faultSensitiveMethod">The fault sensitive function delegate that is invoked until an operation is successful, the amount of retry attempts has been reached, or a failed operation is not considered related to transient fault condition.</param>
        /// <param name="arg1">The first parameter of the function delegate <paramref name="faultSensitiveMethod"/>.</param>
        /// <param name="arg2">The second parameter of the function delegate <paramref name="faultSensitiveMethod"/>.</param>
        /// <param name="arg3">The third parameter of the function delegate <paramref name="faultSensitiveMethod"/>.</param>
        /// <param name="arg4">The fourth parameter of the function delegate <paramref name="faultSensitiveMethod"/>.</param>
        /// <param name="setup">The <see cref="TransientOperationOptions"/> which need to be configured.</param>
        /// <returns>The result from the <paramref name="faultSensitiveMethod"/>.</returns>
        public static Task <TResult> WithFuncAsync <T1, T2, T3, T4, TResult>(Func <T1, T2, T3, T4, Task <TResult> > faultSensitiveMethod, T1 arg1, T2 arg2, T3 arg3, T4 arg4, Action <TransientOperationOptions> setup = null)
        {
            var factory = TaskFuncFactory.Create(faultSensitiveMethod, arg1, arg2, arg3, arg4);

            return(WithFuncAsyncCore(factory, setup));
        }
Exemple #5
0
        /// <summary>
        /// Repetitively executes the specified <paramref name="faultSensitiveMethod"/> until the operation is successful, the amount of retry attempts has been reached, or a failed operation is not considered related to transient fault condition.
        /// </summary>
        /// <typeparam name="T">The type of the parameter of the function delegate <paramref name="faultSensitiveMethod"/>.</typeparam>
        /// <typeparam name="TResult">The type of the return value of the function delegate <paramref name="faultSensitiveMethod"/>.</typeparam>
        /// <param name="faultSensitiveMethod">The fault sensitive function delegate that is invoked until an operation is successful, the amount of retry attempts has been reached, or a failed operation is not considered related to transient fault condition.</param>
        /// <param name="arg">The parameter of the function delegate <paramref name="faultSensitiveMethod"/>.</param>
        /// <param name="setup">The <see cref="TransientOperationOptions"/> which need to be configured.</param>
        /// <returns>The result from the <paramref name="faultSensitiveMethod"/>.</returns>
        public static Task <TResult> WithFuncAsync <T, TResult>(Func <T, Task <TResult> > faultSensitiveMethod, T arg, Action <TransientOperationOptions> setup = null)
        {
            var factory = TaskFuncFactory.Create(faultSensitiveMethod, arg);

            return(WithFuncAsyncCore(factory, setup));
        }
Exemple #6
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);
        }