예제 #1
0
        internal static TResult Implementation <TResult>(
            ExceptionPredicates shouldHandleExceptionPredicates,
            ResultPredicates <TResult> shouldHandleResultPredicates,
            Action <DelegateResult <TResult> > behaviourIfHandle,
            Func <Context, CancellationToken, TResult> action,
            Context context,
            CancellationToken cancellationToken)
        {
            try
            {
                TResult result = action(context, cancellationToken);

                if (shouldHandleResultPredicates.AnyMatch(result))
                {
                    behaviourIfHandle(new DelegateResult <TResult>(result));
                }

                return(result);
            }
            catch (Exception ex)
            {
                Exception handledException = shouldHandleExceptionPredicates.FirstMatchOrDefault(ex);
                if (handledException == null)
                {
                    throw;
                }

                behaviourIfHandle(new DelegateResult <TResult>(handledException));

                handledException.RethrowWithOriginalStackTraceIfDiffersFrom(ex);
                throw;
            }
        }
        internal static async Task <TResult> ImplementationAsync <TResult>(
            ExceptionPredicates shouldHandleExceptionPredicates,
            ResultPredicates <TResult> shouldHandleResultPredicates,
            Func <DelegateResult <TResult>, Task> behaviourIfHandle,
            Func <Context, CancellationToken, Task <TResult> > action,
            Context context,
            CancellationToken cancellationToken,
            bool continueOnCapturedContext)
        {
            try
            {
                TResult result = await action(context, cancellationToken).ConfigureAwait(continueOnCapturedContext);

                if (shouldHandleResultPredicates.AnyMatch(result))
                {
                    await behaviourIfHandle(new DelegateResult <TResult>(result)).ConfigureAwait(continueOnCapturedContext);
                }

                return(result);
            }
            catch (Exception ex)
            {
                Exception handledException = shouldHandleExceptionPredicates.FirstMatchOrDefault(ex);
                if (handledException == null)
                {
                    throw;
                }

                await behaviourIfHandle(new DelegateResult <TResult>(ex)).ConfigureAwait(continueOnCapturedContext);

                handledException.RethrowWithOriginalStackTraceIfDiffersFrom(ex);
                throw;
            }
        }
예제 #3
0
        internal static TResult Implementation <TResult>(
            Func <Context, CancellationToken, TResult> action,
            Context context,
            CancellationToken cancellationToken,
            ExceptionPredicates shouldHandleExceptionPredicates,
            ResultPredicates <TResult> shouldHandleResultPredicates,
            ICircuitController <TResult> breakerController)
        {
            cancellationToken.ThrowIfCancellationRequested();

            breakerController.OnActionPreExecute();

            try
            {
                TResult result = action(context, cancellationToken);

                if (shouldHandleResultPredicates.AnyMatch(result))
                {
                    breakerController.OnActionFailure(new DelegateResult <TResult>(result), context);
                }
                else
                {
                    breakerController.OnActionSuccess(context);
                }

                return(result);
            }
            catch (Exception ex)
            {
                Exception handledException = shouldHandleExceptionPredicates.FirstMatchOrDefault(ex);
                if (handledException == null)
                {
                    throw;
                }

                breakerController.OnActionFailure(new DelegateResult <TResult>(handledException), context);

                if (handledException != ex)
                {
                    ExceptionDispatchInfo.Capture(handledException).Throw();
                }
                throw;
            }
        }
        internal static async Task <TResult> ImplementationAsync <TResult>(
            Func <Context, CancellationToken, Task <TResult> > action,
            Context context,
            CancellationToken cancellationToken,
            bool continueOnCapturedContext,
            ExceptionPredicates shouldHandleExceptionPredicates,
            ResultPredicates <TResult> shouldHandleResultPredicates,
            ICircuitController <TResult> breakerController)
        {
            cancellationToken.ThrowIfCancellationRequested();

            breakerController.OnActionPreExecute();

            try
            {
                TResult result = await action(context, cancellationToken).ConfigureAwait(continueOnCapturedContext);

                if (shouldHandleResultPredicates.AnyMatch(result))
                {
                    breakerController.OnActionFailure(new DelegateResult <TResult>(result), context);
                }
                else
                {
                    breakerController.OnActionSuccess(context);
                }

                return(result);
            }
            catch (Exception ex)
            {
                Exception handledException = shouldHandleExceptionPredicates.FirstMatchOrDefault(ex);
                if (handledException == null)
                {
                    throw;
                }

                breakerController.OnActionFailure(new DelegateResult <TResult>(handledException), context);

                handledException.RethrowWithOriginalStackTraceIfDiffersFrom(ex);
                throw;
            }
        }
예제 #5
0
        internal static async Task <TResult> ImplementationAsync <TResult>(
            Func <Context, CancellationToken, Task <TResult> > action,
            Context context,
            CancellationToken cancellationToken,
            bool continueOnCapturedContext,
            ExceptionPredicates shouldHandleExceptionPredicates,
            ResultPredicates <TResult> shouldHandleResultPredicates,
            Func <Context, ILogger> loggerProvider,
            Action <ILogger, Context, DelegateResult <TResult> > logAction)
        {
            try
            {
                TResult result = await action(context, cancellationToken).ConfigureAwait(continueOnCapturedContext);

                if (!shouldHandleResultPredicates.AnyMatch(result))
                {
                    return(result); // Not an outcome the policy handles - just return it.
                }

                ILogger logger = loggerProvider(context);
                logAction(logger, context, new DelegateResult <TResult>(result));

                // The policy intentionally bubbles the result outwards after logging.
                return(result);
            }
            catch (Exception exception)
            {
                Exception handledException = shouldHandleExceptionPredicates.FirstMatchOrDefault(exception);
                if (handledException == null)
                {
                    throw; // Not an exception the policy handles - propagate the exception.
                }

                ILogger logger = loggerProvider(context);
                logAction(logger, context, new DelegateResult <TResult>(exception));

                // The policy intentionally bubbles the exception outwards after logging.
                handledException.RethrowWithOriginalStackTraceIfDiffersFrom(exception);
                throw;
            }
        }
예제 #6
0
        internal static async Task <TResult> ImplementationAsync <TResult>(
            Func <Context, CancellationToken, Task <TResult> > action,
            Context context,
            CancellationToken cancellationToken,
            ExceptionPredicates shouldHandleExceptionPredicates,
            ResultPredicates <TResult> shouldHandleResultPredicates,
            Func <DelegateResult <TResult>, Context, Task> onFallbackAsync,
            Func <DelegateResult <TResult>, Context, CancellationToken, Task <TResult> > fallbackAction,
            bool continueOnCapturedContext)
        {
            DelegateResult <TResult> delegateOutcome;

            try
            {
                cancellationToken.ThrowIfCancellationRequested();

                TResult result = await action(context, cancellationToken).ConfigureAwait(continueOnCapturedContext);

                if (!shouldHandleResultPredicates.AnyMatch(result))
                {
                    return(result);
                }

                delegateOutcome = new DelegateResult <TResult>(result);
            }
            catch (Exception ex)
            {
                Exception handledException = shouldHandleExceptionPredicates.FirstMatchOrDefault(ex);
                if (handledException == null)
                {
                    throw;
                }

                delegateOutcome = new DelegateResult <TResult>(handledException);
            }

            await onFallbackAsync(delegateOutcome, context).ConfigureAwait(continueOnCapturedContext);

            return(await fallbackAction(delegateOutcome, context, cancellationToken).ConfigureAwait(continueOnCapturedContext));
        }
예제 #7
0
        internal static TResult Implementation <TResult>(
            Func <Context, CancellationToken, TResult> action,
            Context context,
            CancellationToken cancellationToken,
            ExceptionPredicates shouldHandleExceptionPredicates,
            ResultPredicates <TResult> shouldHandleResultPredicates,
            Action <DelegateResult <TResult>, Context> onFallback,
            Func <DelegateResult <TResult>, Context, CancellationToken, TResult> fallbackAction)
        {
            DelegateResult <TResult> delegateOutcome;

            try
            {
                cancellationToken.ThrowIfCancellationRequested();

                TResult result = action(context, cancellationToken);

                if (!shouldHandleResultPredicates.AnyMatch(result))
                {
                    return(result);
                }

                delegateOutcome = new DelegateResult <TResult>(result);
            }
            catch (Exception ex)
            {
                Exception handledException = shouldHandleExceptionPredicates.FirstMatchOrDefault(ex);
                if (handledException == null)
                {
                    throw;
                }

                delegateOutcome = new DelegateResult <TResult>(handledException);
            }

            onFallback(delegateOutcome, context);

            return(fallbackAction(delegateOutcome, context, cancellationToken));
        }
예제 #8
0
        private static void LogException <TResult>(Exception exception, Context context, ExceptionPredicates shouldHandleExceptionPredicates, Func <Context, ILogger> loggerProvider, Action <ILogger, Context, DelegateResult <TResult> > logAction)
        {
            var handledException = shouldHandleExceptionPredicates.FirstMatchOrDefault(exception);

            if (handledException != null)
            {
                var logger = loggerProvider(context);
                logAction(logger, context, new DelegateResult <TResult>(exception));

                // The policy intentionally bubbles the exception outwards after logging.
                handledException.RethrowWithOriginalStackTraceIfDiffersFrom(exception);
            }
        }
예제 #9
0
 internal static async Task <TResult> ImplementationAsync <TResult>(Func <Context, CancellationToken, Task <TResult> > action, Context context, bool continueOnCapturedContext, ExceptionPredicates shouldHandleExceptionPredicates, ResultPredicates <TResult> shouldHandleResultPredicates, Func <Context, ILogger> loggerProvider, Action <ILogger, Context, DelegateResult <TResult> > logAction, CancellationToken cancellationToken)
 {
     try
     {
         return(LogResult(await action(context, cancellationToken).ConfigureAwait(continueOnCapturedContext), context, shouldHandleResultPredicates, loggerProvider, logAction));
     }
     catch (Exception exception)
     {
         LogException(exception, context, shouldHandleExceptionPredicates, loggerProvider, logAction);
         throw;
     }
 }
예제 #10
0
 internal static TResult Implementation <TResult>(Func <Context, CancellationToken, TResult> action, Context context, ExceptionPredicates shouldHandleExceptionPredicates, ResultPredicates <TResult> shouldHandleResultPredicates, Func <Context, ILogger> loggerProvider, Action <ILogger, Context, DelegateResult <TResult> > logAction, CancellationToken cancellationToken)
 {
     try
     {
         return(LogResult(action(context, cancellationToken), context, shouldHandleResultPredicates, loggerProvider, logAction));
     }
     catch (Exception exception)
     {
         LogException(exception, context, shouldHandleExceptionPredicates, loggerProvider, logAction);
         throw;
     }
 }
예제 #11
0
 /// <summary>
 /// Constructs a new instance of a derived <see cref="AsyncPolicy"/> type with the passed <paramref name="exceptionPredicates"/>.
 /// </summary>
 /// <param name="exceptionPredicates">Predicates indicating which exceptions the policy should handle. </param>
 internal AsyncPolicy(ExceptionPredicates exceptionPredicates)
     : base(exceptionPredicates)
 {
 }
        internal static TResult Implementation <TResult>(
            Func <Context, CancellationToken, TResult> action,      // The delegate the user passed to execute
            Context context,                                        // The context the user passed to execute (never null; Polly provides one if user does not)
            CancellationToken cancellationToken,                    // The cancellation token the user passed to execute; for co-operative cancellation to be effective, policy implementations should honour it at suitable points in the execution.
            ExceptionPredicates shouldHandleExceptionPredicates,    // The exceptions the policy has been configured to handle.
            ResultPredicates <TResult> shouldHandleResultPredicates // The results the policy has been configured to handle.

            /* The implementation should receive at least the above parameters,
             * but more parameters can also be passed: eg anything the policy was configured with. */
            )
        {
            /*
             * Code your policy implementation (for synchronous executions) in this method.
             *
             * This:
             *
             *    TResult result = action(context, cancellationToken);
             *
             * is the code which executes the delegate which the caller passed to the policy.Execute(...) call.
             *
             *
             * Your custom policy can do anything around that call:
             *
             * - do something extra before execution (as Polly's CachePolicy does - it checks the cache)
             * - do something extra after execution  (as Polly's CachePolicy does - it stores in the cache a result returned from the execution)
             * - inject something into the execution (as Polly's TimeoutPolicy does - it injects an extra CancellationToken)
             * - delay execution                     (as Simmy's InjectLatencyPolicy does; as Polly's BulkheadEngine does if there is not capacity)
             * - execute it multiple times           (as Polly's RetryPolicy does)
             * - choose not to execute it at all     (as Polly's CircuitBreakerEngine and BulkheadEngine sometimes do)
             *
             * The template below demonstrates how to use the exception predicates and result predicates - the information the user configured with Policy.Handle<Exception>(...) and .HandleResult(...)
             *
             * A Reactive policy handles exceptions and results.  For policies not handling exceptions, see ProactiveFooPolicy.
             *
             */


            try
            {
                TResult result = action(context, cancellationToken);


                if (!shouldHandleResultPredicates.AnyMatch(result))
                {
                    return(result); // Not an outcome your policy handles - just return it.
                }

                // ==============================================================
                /* Code here the way your policy handles the return values it is configured to handle (if it is intended to handle results as well as exceptions). */
                // ==============================================================



                // The policy must eventually return some result.
                // The following line here just returns the result from the underlying call (perhaps after the policy has done some processing based on it)
                // but a policy could equally manipulate the result, substitute the result with another, etc.
                return(result);
            }
            catch (Exception ex)
            {
                Exception handledException = shouldHandleExceptionPredicates.FirstMatchOrDefault(ex);
                if (handledException == null)
                {
                    throw; // Not an exception your policy handles - propagate the exception.
                }

                // ==============================================================
                /* Code here the way your policy handles the exceptions it is configured to handle. */
                // ==============================================================



                // The policy must eventually return some result or throw.
                // The lines here just rethrow the exception (perhaps after the policy has done some processing based on it)
                // but a policy could equally manipulate the exception, throw a different one, return a substitute result, etc.

                // The following line here rethrows the handled exception with original stacktrace;
                // the helper method makes the stack trace correct if the handled exception was an inner exception caught with Polly's HandleInner<>() syntax.
                handledException.RethrowWithOriginalStackTraceIfDiffersFrom(ex);
                throw; // Extra throw statement never hit; just to make the compiler not report: 'Not all code paths return a value'
            }
        }
예제 #13
0
        internal static async Task <TResult> ImplementationAsync <TResult>(
            Func <Context, CancellationToken, Task <TResult> > action,
            Context context,
            CancellationToken cancellationToken,
            ExceptionPredicates shouldRetryExceptionPredicates,
            ResultPredicates <TResult> shouldRetryResultPredicates,
            Func <DelegateResult <TResult>, TimeSpan, int, Context, Task> onRetryAsync,
            int permittedRetryCount = Int32.MaxValue,
            IEnumerable <TimeSpan> sleepDurationsEnumerable = null,
            Func <int, DelegateResult <TResult>, Context, TimeSpan> sleepDurationProvider = null,
            bool continueOnCapturedContext = false)
        {
            int tryCount = 0;
            IEnumerator <TimeSpan> sleepDurationsEnumerator = sleepDurationsEnumerable?.GetEnumerator();

            try
            {
                while (true)
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    bool canRetry;
                    DelegateResult <TResult> outcome;

                    try
                    {
                        TResult result = await action(context, cancellationToken).ConfigureAwait(continueOnCapturedContext);

                        if (!shouldRetryResultPredicates.AnyMatch(result))
                        {
                            return(result);
                        }

                        canRetry = tryCount < permittedRetryCount && (sleepDurationsEnumerable == null || sleepDurationsEnumerator.MoveNext());

                        if (!canRetry)
                        {
                            return(result);
                        }

                        outcome = new DelegateResult <TResult>(result);
                    }
                    catch (Exception ex)
                    {
                        Exception handledException = shouldRetryExceptionPredicates.FirstMatchOrDefault(ex);
                        if (handledException == null)
                        {
                            throw;
                        }

                        canRetry = tryCount < permittedRetryCount && (sleepDurationsEnumerable == null || sleepDurationsEnumerator.MoveNext());

                        if (!canRetry)
                        {
                            handledException.RethrowWithOriginalStackTraceIfDiffersFrom(ex);
                            throw;
                        }

                        outcome = new DelegateResult <TResult>(handledException);
                    }

                    if (tryCount < int.MaxValue)
                    {
                        tryCount++;
                    }

                    TimeSpan waitDuration = sleepDurationsEnumerator?.Current ?? (sleepDurationProvider?.Invoke(tryCount, outcome, context) ?? TimeSpan.Zero);

                    await onRetryAsync(outcome, waitDuration, tryCount, context).ConfigureAwait(continueOnCapturedContext);

                    if (waitDuration > TimeSpan.Zero)
                    {
                        await SystemClock.SleepAsync(waitDuration, cancellationToken).ConfigureAwait(continueOnCapturedContext);
                    }
                }
            }
            finally
            {
                sleepDurationsEnumerator?.Dispose();
            }
        }
예제 #14
0
 /// <summary>
 /// Constructs a new instance of a derived <see cref="Policy{TResult}"/> type with the passed <paramref name="exceptionPredicates"/> and <paramref name="resultPredicates"/>.
 /// </summary>
 /// <param name="exceptionPredicates">Predicates indicating which exceptions the policy should handle.</param>
 /// <param name="resultPredicates">Predicates indicating which results the policy should handle.</param>
 internal Policy(ExceptionPredicates exceptionPredicates, ResultPredicates <TResult> resultPredicates)
     : base(exceptionPredicates, resultPredicates)
 {
 }