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; } }
private static TResult LogResult <TResult>(TResult result, Context context, ResultPredicates <TResult> shouldHandleResultPredicates, Func <Context, ILogger> loggerProvider, Action <ILogger, Context, DelegateResult <TResult> > logAction) { if (shouldHandleResultPredicates.AnyMatch(result)) { var logger = loggerProvider(context); logAction(logger, context, new DelegateResult <TResult>(result)); } return(result); }
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; } }
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; } }
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)); }
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)); }
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; } }
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; } }
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' } }
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(); } }
/// <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) { }