diff --git a/src/Polly.Contrib.Simmy.Specs/Behavior/InjectBehaviourAsyncWithOptionsSpecs.cs b/src/Polly.Contrib.Simmy.Specs/Behavior/InjectBehaviourAsyncWithOptionsSpecs.cs index eed3646..10609dc 100644 --- a/src/Polly.Contrib.Simmy.Specs/Behavior/InjectBehaviourAsyncWithOptionsSpecs.cs +++ b/src/Polly.Contrib.Simmy.Specs/Behavior/InjectBehaviourAsyncWithOptionsSpecs.cs @@ -109,6 +109,60 @@ public void Should_inject_behaviour_before_executing_user_delegate() injectedBehaviourExecuted.Should().BeTrue(); } + #region BeforeInject + [Fact] + public async Task Should_call_before_inject_callback_before_injecting_behavior() + { + var beforeInjectExecuted = false; + var injectedBehaviourExecuted = false; + + var policy = MonkeyPolicy.InjectBehaviourAsync(with => + with.Behaviour(async () => + { + beforeInjectExecuted.Should().BeTrue(); + injectedBehaviourExecuted = true; + }) + .BeforeInject(async (context, cancellation) => + { + injectedBehaviourExecuted.Should().BeFalse(); + beforeInjectExecuted = true; + }) + .InjectionRate(0.6) + .Enabled() + ); + + await policy.ExecuteAsync(() => Task.CompletedTask); + + beforeInjectExecuted.Should().BeTrue(); + injectedBehaviourExecuted.Should().BeTrue(); + } + + [Fact] + public async Task Should_not_call_before_inject_callback_if_not_injecting() + { + var beforeInjectExecuted = false; + var behaviorExecuted = false; + + var policy = MonkeyPolicy.InjectBehaviourAsync(with => + with.Behaviour(async () => + { + behaviorExecuted = true; + }) + .BeforeInject(async (context, cancellation) => + { + beforeInjectExecuted = true; + }) + .InjectionRate(0.4) + .Enabled() + ); + + await policy.ExecuteAsync(() => Task.CompletedTask); + + beforeInjectExecuted.Should().BeFalse(); + behaviorExecuted.Should().BeFalse(); + } + #endregion + #region invalid threshold on configuration and execution time [Fact] diff --git a/src/Polly.Contrib.Simmy.Specs/Behavior/InjectBehaviourWithOptionsSpecs.cs b/src/Polly.Contrib.Simmy.Specs/Behavior/InjectBehaviourWithOptionsSpecs.cs index 6f68acb..1446052 100644 --- a/src/Polly.Contrib.Simmy.Specs/Behavior/InjectBehaviourWithOptionsSpecs.cs +++ b/src/Polly.Contrib.Simmy.Specs/Behavior/InjectBehaviourWithOptionsSpecs.cs @@ -91,6 +91,60 @@ public void Should_inject_behaviour_before_executing_user_delegate() injectedBehaviourExecuted.Should().BeTrue(); } + #region BeforeInject + [Fact] + public void Should_call_before_inject_callback_before_injecting_behavior() + { + var beforeInjectExecuted = false; + var injectedBehaviourExecuted = false; + + var policy = MonkeyPolicy.InjectBehaviour(with => + with.Behaviour(() => + { + beforeInjectExecuted.Should().BeTrue(); + injectedBehaviourExecuted = true; + }) + .BeforeInject((context, cancellation) => + { + injectedBehaviourExecuted.Should().BeFalse(); + beforeInjectExecuted = true; + }) + .InjectionRate(0.6) + .Enabled() + ); + + policy.Execute(() => { }); + + beforeInjectExecuted.Should().BeTrue(); + injectedBehaviourExecuted.Should().BeTrue(); + } + + [Fact] + public void Should_not_call_before_inject_callback_if_not_injecting() + { + var beforeInjectExecuted = false; + var behaviorExecuted = false; + + var policy = MonkeyPolicy.InjectBehaviour(with => + with.Behaviour(() => + { + behaviorExecuted = true; + }) + .BeforeInject((context, cancellation) => + { + beforeInjectExecuted = true; + }) + .InjectionRate(0.4) + .Enabled() + ); + + policy.Execute(() => { }); + + beforeInjectExecuted.Should().BeFalse(); + behaviorExecuted.Should().BeFalse(); + } + #endregion + #region invalid threshold on configuration and execution time [Fact] diff --git a/src/Polly.Contrib.Simmy.Specs/Latency/InjectLatencyAsyncWithOptionsSpecs.cs b/src/Polly.Contrib.Simmy.Specs/Latency/InjectLatencyAsyncWithOptionsSpecs.cs index 59f0970..30f1994 100644 --- a/src/Polly.Contrib.Simmy.Specs/Latency/InjectLatencyAsyncWithOptionsSpecs.cs +++ b/src/Polly.Contrib.Simmy.Specs/Latency/InjectLatencyAsyncWithOptionsSpecs.cs @@ -105,6 +105,50 @@ public async Task InjectLatency_Context_Free_Should_Not_Introduce_Delay_If_Injec #endregion + #region BeforeInject + [Fact] + public async Task Should_call_before_inject_callback_if_injecting() + { + var beforeInjectExecuted = false; + var executed = false; + + var policy = MonkeyPolicy.InjectLatencyAsync(with => + with.Latency(TimeSpan.FromMilliseconds(1)) + .BeforeInject(async (context, cancellation) => { beforeInjectExecuted = true; }) + .InjectionRate(0.6) + .Enabled()); + + await policy.ExecuteAsync(async () => + { + beforeInjectExecuted.Should().BeTrue(); + executed = true; + }); + executed.Should().BeTrue(); + beforeInjectExecuted.Should().BeTrue(); + } + + [Fact] + public async Task Should_not_call_before_inject_callback_if_not_injecting() + { + var beforeInjectExecuted = false; + var executed = false; + + var policy = MonkeyPolicy.InjectLatencyAsync(with => + with.Latency(TimeSpan.FromMilliseconds(1)) + .BeforeInject(async (context, cancellation) => { beforeInjectExecuted = true; }) + .InjectionRate(0.4) + .Enabled()); + + await policy.ExecuteAsync(async () => + { + beforeInjectExecuted.Should().BeFalse(); + executed = true; + }); + executed.Should().BeTrue(); + beforeInjectExecuted.Should().BeFalse(); + } + #endregion + #region With Context [Fact] diff --git a/src/Polly.Contrib.Simmy.Specs/Latency/InjectLatencyWithOptionsSpecs.cs b/src/Polly.Contrib.Simmy.Specs/Latency/InjectLatencyWithOptionsSpecs.cs index 8142c82..e6720d1 100644 --- a/src/Polly.Contrib.Simmy.Specs/Latency/InjectLatencyWithOptionsSpecs.cs +++ b/src/Polly.Contrib.Simmy.Specs/Latency/InjectLatencyWithOptionsSpecs.cs @@ -99,6 +99,50 @@ public void InjectLatency_Context_Free_Should_Not_Introduce_Delay_If_InjectionRa #endregion + #region BeforeInject + [Fact] + public void Should_call_before_inject_callback_if_injecting() + { + var beforeInjectExecuted = false; + var executed = false; + + var policy = MonkeyPolicy.InjectLatency(with => + with.Latency(TimeSpan.FromMilliseconds(1)) + .BeforeInject((context, cancellation) => { beforeInjectExecuted = true; }) + .InjectionRate(0.6) + .Enabled()); + + policy.Execute(() => + { + beforeInjectExecuted.Should().BeTrue(); + executed = true; + }); + executed.Should().BeTrue(); + beforeInjectExecuted.Should().BeTrue(); + } + + [Fact] + public void Should_not_call_before_inject_callback_if_not_injecting() + { + var beforeInjectExecuted = false; + var executed = false; + + var policy = MonkeyPolicy.InjectLatency(with => + with.Latency(TimeSpan.FromMilliseconds(1)) + .BeforeInject((context, cancellation) => { beforeInjectExecuted = true; }) + .InjectionRate(0.4) + .Enabled()); + + policy.Execute(() => + { + beforeInjectExecuted.Should().BeFalse(); + executed = true; + }); + executed.Should().BeTrue(); + beforeInjectExecuted.Should().BeFalse(); + } + #endregion + #region With Context [Fact] diff --git a/src/Polly.Contrib.Simmy.Specs/Outcomes/InjectFaultAsyncWithOptionsSpecs.cs b/src/Polly.Contrib.Simmy.Specs/Outcomes/InjectFaultAsyncWithOptionsSpecs.cs index 7a4312c..830b18a 100644 --- a/src/Polly.Contrib.Simmy.Specs/Outcomes/InjectFaultAsyncWithOptionsSpecs.cs +++ b/src/Polly.Contrib.Simmy.Specs/Outcomes/InjectFaultAsyncWithOptionsSpecs.cs @@ -77,6 +77,46 @@ public void InjectFault_Context_Free_Enabled_Should_execute_user_delegate_not_th } #endregion + #region BeforeInject + [Fact] + public async Task Should_call_before_inject_callback_if_injecting() + { + var beforeInjectExecuted = false; + var executed = false; + + var policy = MonkeyPolicy.InjectExceptionAsync(with => + with.Fault(new Exception()) + .BeforeInject(async (context, cancellation) => { beforeInjectExecuted = true; }) + .InjectionRate(0.6) + .Enabled()); + + policy.Awaiting(async p => await p.ExecuteAsync(async () => { executed = true; })).ShouldThrowExactly(); + executed.Should().BeFalse(); + beforeInjectExecuted.Should().BeTrue(); + } + + [Fact] + public async Task Should_not_call_before_inject_callback_if_not_injecting() + { + var beforeInjectExecuted = false; + var executed = false; + + var policy = MonkeyPolicy.InjectExceptionAsync(with => + with.Fault(new Exception()) + .BeforeInject(async (context, cancellation) => { beforeInjectExecuted = true; }) + .InjectionRate(0.4) + .Enabled()); + + await policy.ExecuteAsync(async () => + { + beforeInjectExecuted.Should().BeFalse(); + executed = true; + }); + executed.Should().BeTrue(); + beforeInjectExecuted.Should().BeFalse(); + } + #endregion + #region Basic Overload, Exception, With Context [Fact] public void InjectFault_With_Context_Should_not_execute_user_delegate_async() diff --git a/src/Polly.Contrib.Simmy.Specs/Outcomes/InjectFaultTResultAsyncWithOptionsSpecs.cs b/src/Polly.Contrib.Simmy.Specs/Outcomes/InjectFaultTResultAsyncWithOptionsSpecs.cs index 10e7c00..d74e047 100644 --- a/src/Polly.Contrib.Simmy.Specs/Outcomes/InjectFaultTResultAsyncWithOptionsSpecs.cs +++ b/src/Polly.Contrib.Simmy.Specs/Outcomes/InjectFaultTResultAsyncWithOptionsSpecs.cs @@ -63,6 +63,50 @@ public void InjectFault_Context_Free_Enabled_Should_execute_user_delegate_async( } #endregion + #region BeforeInject + [Fact] + public async Task Should_call_before_inject_callback_if_injecting() + { + var beforeInjectExecuted = false; + var executed = false; + + var policy = MonkeyPolicy.InjectResultAsync(with => + with.Fault(new Exception()) + .BeforeInject(async (context, cancellation) => { beforeInjectExecuted = true; }) + .InjectionRate(0.6) + .Enabled()); + + policy.Awaiting(async p => await p.ExecuteAsync(async () => { executed = true; return ResultPrimitive.Good; })) + .ShouldThrowExactly(); + + executed.Should().BeFalse(); + beforeInjectExecuted.Should().BeTrue(); + } + + [Fact] + public async Task Should_not_call_before_inject_callback_if_not_injecting() + { + var beforeInjectExecuted = false; + var executed = false; + + var policy = MonkeyPolicy.InjectResultAsync(with => + with.Fault(new Exception()) + .BeforeInject(async (context, cancellation) => { beforeInjectExecuted = true; }) + .InjectionRate(0.4) + .Enabled()); + + await policy.ExecuteAsync(async () => + { + beforeInjectExecuted.Should().BeFalse(); + executed = true; + return ResultPrimitive.Good; + }); + executed.Should().BeTrue(); + beforeInjectExecuted.Should().BeFalse(); + } + #endregion + + #region Basic Overload, Exception, With Context [Fact] public void InjectFault_With_Context_Should_not_execute_user_delegate_async() diff --git a/src/Polly.Contrib.Simmy.Specs/Outcomes/InjectFaultTResultWithOptionsSpecs.cs b/src/Polly.Contrib.Simmy.Specs/Outcomes/InjectFaultTResultWithOptionsSpecs.cs index 7986c04..5722012 100644 --- a/src/Polly.Contrib.Simmy.Specs/Outcomes/InjectFaultTResultWithOptionsSpecs.cs +++ b/src/Polly.Contrib.Simmy.Specs/Outcomes/InjectFaultTResultWithOptionsSpecs.cs @@ -63,6 +63,49 @@ public void InjectFaultContext_Free_Enabled_Should_execute_user_delegate() } #endregion + #region BeforeInject + [Fact] + public void Should_call_before_inject_callback_if_injecting() + { + var beforeInjectExecuted = false; + var executed = false; + + var policy = MonkeyPolicy.InjectResult(with => + with.Fault(new Exception()) + .BeforeInject((context, cancellation) => { beforeInjectExecuted = true; }) + .InjectionRate(0.6) + .Enabled()); + + policy.Invoking(p => p.Execute(() => { executed = true; return ResultPrimitive.Good; })) + .ShouldThrowExactly(); + + executed.Should().BeFalse(); + beforeInjectExecuted.Should().BeTrue(); + } + + [Fact] + public void Should_not_call_before_inject_callback_if_not_injecting() + { + var beforeInjectExecuted = false; + var executed = false; + + var policy = MonkeyPolicy.InjectResult(with => + with.Fault(new Exception()) + .BeforeInject((context, cancellation) => { beforeInjectExecuted = true; }) + .InjectionRate(0.4) + .Enabled()); + + policy.Execute(() => + { + beforeInjectExecuted.Should().BeFalse(); + executed = true; + return ResultPrimitive.Good; + }); + executed.Should().BeTrue(); + beforeInjectExecuted.Should().BeFalse(); + } + #endregion + #region Basic Overload, Result as Fault, With Context [Fact] public void InjectFaultWith_Context_Should_not_execute_user_delegate() diff --git a/src/Polly.Contrib.Simmy.Specs/Outcomes/InjectFaultWithOptionsSpecs.cs b/src/Polly.Contrib.Simmy.Specs/Outcomes/InjectFaultWithOptionsSpecs.cs index e81f8d0..1811dfc 100644 --- a/src/Polly.Contrib.Simmy.Specs/Outcomes/InjectFaultWithOptionsSpecs.cs +++ b/src/Polly.Contrib.Simmy.Specs/Outcomes/InjectFaultWithOptionsSpecs.cs @@ -78,6 +78,47 @@ public void InjectFault_Context_Free_Enabled_Should_execute_user_delegate_not_th #endregion + #region BeforeInject + [Fact] + public void Should_call_before_inject_callback_if_injecting() + { + var beforeInjectExecuted = false; + var executed = false; + + var policy = MonkeyPolicy.InjectException(with => + with.Fault(new Exception()) + .BeforeInject((context, cancellation) => { beforeInjectExecuted = true; }) + .InjectionRate(0.6) + .Enabled()); + + policy.Invoking(p => p.Execute(() => { executed = true; })).ShouldThrowExactly(); + + beforeInjectExecuted.Should().BeTrue(); + executed.Should().BeFalse(); + } + + [Fact] + public void Should_not_call_before_inject_callback_if_not_injecting() + { + var beforeInjectExecuted = false; + var executed = false; + + var policy = MonkeyPolicy.InjectException(with => + with.Fault(new Exception()) + .BeforeInject((context, cancellation) => { beforeInjectExecuted = true; }) + .InjectionRate(0.4) + .Enabled()); + + policy.Execute(() => + { + beforeInjectExecuted.Should().BeFalse(); + executed = true; + }); + executed.Should().BeTrue(); + beforeInjectExecuted.Should().BeFalse(); + } + #endregion + #region Basic Overload, Exception, With Context [Fact] public void InjectFault_With_Context_Should_not_execute_user_delegate() diff --git a/src/Polly.Contrib.Simmy/AsyncMonkeyEngine.cs b/src/Polly.Contrib.Simmy/AsyncMonkeyEngine.cs index 8daad49..a0e32ea 100644 --- a/src/Polly.Contrib.Simmy/AsyncMonkeyEngine.cs +++ b/src/Polly.Contrib.Simmy/AsyncMonkeyEngine.cs @@ -41,10 +41,15 @@ internal static async Task InjectBehaviourImplementationAsync( Func injectedBehaviour, Func> injectionRate, Func> enabled, + Func beforeInjectCallback, bool continueOnCapturedContext) { if (await ShouldInjectAsync(context, cancellationToken, injectionRate, enabled, continueOnCapturedContext).ConfigureAwait(continueOnCapturedContext)) { + if (beforeInjectCallback != null) + { + await beforeInjectCallback(context, cancellationToken); + } await injectedBehaviour(context, cancellationToken).ConfigureAwait(continueOnCapturedContext); } @@ -60,6 +65,7 @@ internal static async Task InjectExceptionImplementationAsync( Func> injectedException, Func> injectionRate, Func> enabled, + Func beforeInjectCallback, bool continueOnCapturedContext) { if (await ShouldInjectAsync(context, cancellationToken, injectionRate, enabled, continueOnCapturedContext).ConfigureAwait(continueOnCapturedContext)) @@ -71,6 +77,10 @@ internal static async Task InjectExceptionImplementationAsync( if (exception != null) { + if (beforeInjectCallback != null) + { + await beforeInjectCallback(context, cancellationToken); + } throw exception; } } @@ -85,10 +95,15 @@ internal static async Task InjectResultImplementationAsync( Func> injectedResult, Func> injectionRate, Func> enabled, + Func beforeInjectCallback, bool continueOnCapturedContext) { if (await ShouldInjectAsync(context, cancellationToken, injectionRate, enabled, continueOnCapturedContext).ConfigureAwait(continueOnCapturedContext)) { + if (beforeInjectCallback != null) + { + await beforeInjectCallback(context, cancellationToken); + } return await injectedResult(context, cancellationToken).ConfigureAwait(continueOnCapturedContext); } diff --git a/src/Polly.Contrib.Simmy/Behavior/AsyncInjectBehaviourPolicy.cs b/src/Polly.Contrib.Simmy/Behavior/AsyncInjectBehaviourPolicy.cs index 2e6c4ab..068d4bf 100644 --- a/src/Polly.Contrib.Simmy/Behavior/AsyncInjectBehaviourPolicy.cs +++ b/src/Polly.Contrib.Simmy/Behavior/AsyncInjectBehaviourPolicy.cs @@ -10,6 +10,7 @@ namespace Polly.Contrib.Simmy.Behavior public class AsyncInjectBehaviourPolicy : AsyncMonkeyPolicy { private readonly Func _behaviour; + private readonly Func _beforeInjectCallback; [Obsolete] internal AsyncInjectBehaviourPolicy(Func behaviour, Func> injectionRate, Func> enabled) @@ -22,6 +23,7 @@ internal AsyncInjectBehaviourPolicy(InjectBehaviourAsyncOptions options) : base(options.InjectionRate, options.Enabled) { _behaviour = options.BehaviourInternal ?? throw new ArgumentNullException(nameof(options.BehaviourInternal)); + _beforeInjectCallback = options.BeforeInjectCallback; } /// @@ -35,6 +37,7 @@ protected override Task ImplementationAsync(Func ImplementationAsync(Func : AsyncMonkeyPolicy { private readonly Func _behaviour; + private readonly Func _beforeInjectCallback; [Obsolete] internal AsyncInjectBehaviourPolicy(Func behaviour, Func> injectionRate, Func> enabled) @@ -58,6 +62,7 @@ internal AsyncInjectBehaviourPolicy(InjectBehaviourAsyncOptions options) : base(options.InjectionRate, options.Enabled) { _behaviour = options.BehaviourInternal ?? throw new ArgumentNullException(nameof(options.BehaviourInternal)); + _beforeInjectCallback = options.BeforeInjectCallback; } /// @@ -70,6 +75,7 @@ protected override Task ImplementationAsync(Func _behaviour; + private readonly Action _beforeInjectCallback; [Obsolete] internal InjectBehaviourPolicy(Action behaviour, Func injectionRate, Func enabled) @@ -21,6 +22,7 @@ internal InjectBehaviourPolicy(InjectBehaviourOptions options) : base(options.InjectionRate, options.Enabled) { _behaviour = options.BehaviourInternal ?? throw new ArgumentNullException(nameof(options.BehaviourInternal)); + _beforeInjectCallback = options.BeforeInjectCallback; } /// @@ -32,7 +34,8 @@ protected override TResult Implementation(Func _behaviour(ctx, ct), InjectionRate, - Enabled); + Enabled, + _beforeInjectCallback); } } /// @@ -42,6 +45,7 @@ protected override TResult Implementation(Func : MonkeyPolicy { private readonly Action _behaviour; + private readonly Action _beforeInjectCallback; [Obsolete] internal InjectBehaviourPolicy(Action behaviour, Func injectionRate, Func enabled) @@ -54,6 +58,7 @@ internal InjectBehaviourPolicy(InjectBehaviourOptions options) : base(options.InjectionRate, options.Enabled) { _behaviour = options.BehaviourInternal ?? throw new ArgumentNullException(nameof(options.BehaviourInternal)); + _beforeInjectCallback = options.BeforeInjectCallback; } /// @@ -65,7 +70,8 @@ protected override TResult Implementation(Func _behaviour(ctx, ct), InjectionRate, - Enabled); + Enabled, + _beforeInjectCallback); } } } diff --git a/src/Polly.Contrib.Simmy/InjectOptionsAsyncBase.cs b/src/Polly.Contrib.Simmy/InjectOptionsAsyncBase.cs index 27ba934..0e48c46 100644 --- a/src/Polly.Contrib.Simmy/InjectOptionsAsyncBase.cs +++ b/src/Polly.Contrib.Simmy/InjectOptionsAsyncBase.cs @@ -18,5 +18,10 @@ public abstract class InjectOptionsAsyncBase /// Lambda to check if this policy is enabled in current context /// internal Func> Enabled { get; set; } + + /// + /// Lambda to call immediately before injecting + /// + internal virtual Func BeforeInjectCallback { get; set; } } } \ No newline at end of file diff --git a/src/Polly.Contrib.Simmy/InjectOptionsAsyncBaseExtensions.cs b/src/Polly.Contrib.Simmy/InjectOptionsAsyncBaseExtensions.cs index 3879aed..d8d6103 100644 --- a/src/Polly.Contrib.Simmy/InjectOptionsAsyncBaseExtensions.cs +++ b/src/Polly.Contrib.Simmy/InjectOptionsAsyncBaseExtensions.cs @@ -60,5 +60,17 @@ public static InjectOptionsAsyncBase InjectionRate(this InjectOptionsAsyncBase o options.InjectionRate = injectionRateProvider; return options; } + + /// + /// Configure a callback to be run immediately before injecting chaos. + /// + /// The configuration object. + /// A delegate to be run immediately before injecting chaos. + /// + public static InjectOptionsAsyncBase BeforeInject(this InjectOptionsAsyncBase options, Func beforeInjectCallback) + { + options.BeforeInjectCallback = beforeInjectCallback; + return options; + } } } diff --git a/src/Polly.Contrib.Simmy/InjectOptionsBase.cs b/src/Polly.Contrib.Simmy/InjectOptionsBase.cs index 07f4dcb..de00877 100644 --- a/src/Polly.Contrib.Simmy/InjectOptionsBase.cs +++ b/src/Polly.Contrib.Simmy/InjectOptionsBase.cs @@ -17,5 +17,10 @@ public abstract class InjectOptionsBase /// Lambda to check if this policy is enabled in current context /// internal Func Enabled { get; set; } + + /// + /// Lambda to call immediately before injecting + /// + internal Action BeforeInjectCallback { get; set; } } } diff --git a/src/Polly.Contrib.Simmy/InjectOptionsBaseExtensions.cs b/src/Polly.Contrib.Simmy/InjectOptionsBaseExtensions.cs index ac24f7b..a6b4e09 100644 --- a/src/Polly.Contrib.Simmy/InjectOptionsBaseExtensions.cs +++ b/src/Polly.Contrib.Simmy/InjectOptionsBaseExtensions.cs @@ -59,5 +59,17 @@ public static InjectOptionsBase InjectionRate(this InjectOptionsBase options, Fu options.InjectionRate = injectionRateProvider; return options; } + + /// + /// Configure a callback to be run immediately before injecting chaos. + /// + /// The configuration object. + /// A delegate to be run immediately before injecting chaos. + /// + public static InjectOptionsBase BeforeInject(this InjectOptionsBase options, Action beforeInjectCallback) + { + options.BeforeInjectCallback = beforeInjectCallback; + return options; + } } } diff --git a/src/Polly.Contrib.Simmy/Latency/AsyncInjectLatencyPolicy.cs b/src/Polly.Contrib.Simmy/Latency/AsyncInjectLatencyPolicy.cs index ba1ee09..75f8415 100644 --- a/src/Polly.Contrib.Simmy/Latency/AsyncInjectLatencyPolicy.cs +++ b/src/Polly.Contrib.Simmy/Latency/AsyncInjectLatencyPolicy.cs @@ -11,6 +11,7 @@ namespace Polly.Contrib.Simmy.Latency public class AsyncInjectLatencyPolicy : AsyncMonkeyPolicy { private readonly Func> _latencyProvider; + private readonly Func _beforeInjectCallback; [Obsolete] internal AsyncInjectLatencyPolicy( @@ -26,6 +27,7 @@ internal AsyncInjectLatencyPolicy(InjectLatencyAsyncOptions options) : base(options.InjectionRate, options.Enabled) { _latencyProvider = options.LatencyInternal ?? throw new ArgumentNullException(nameof(options.LatencyInternal)); + _beforeInjectCallback = options.BeforeInjectCallback; } /// @@ -52,6 +54,7 @@ await SystemClock.SleepAsync( }, InjectionRate, Enabled, + _beforeInjectCallback, continueOnCapturedContext); } } @@ -62,6 +65,7 @@ await SystemClock.SleepAsync( public class AsyncInjectLatencyPolicy : AsyncMonkeyPolicy { private readonly Func> _latencyProvider; + private readonly Func _beforeInjectCallback; [Obsolete] internal AsyncInjectLatencyPolicy( @@ -77,6 +81,7 @@ internal AsyncInjectLatencyPolicy(InjectLatencyAsyncOptions options) : base(options.InjectionRate, options.Enabled) { _latencyProvider = options.LatencyInternal ?? throw new ArgumentNullException(nameof(options.LatencyInternal)); + _beforeInjectCallback = options.BeforeInjectCallback; } /// @@ -103,6 +108,7 @@ await SystemClock.SleepAsync( }, InjectionRate, Enabled, + _beforeInjectCallback, continueOnCapturedContext); } } diff --git a/src/Polly.Contrib.Simmy/Latency/InjectLatencyPolicy.cs b/src/Polly.Contrib.Simmy/Latency/InjectLatencyPolicy.cs index a4d372c..f24d67d 100644 --- a/src/Polly.Contrib.Simmy/Latency/InjectLatencyPolicy.cs +++ b/src/Polly.Contrib.Simmy/Latency/InjectLatencyPolicy.cs @@ -10,6 +10,7 @@ namespace Polly.Contrib.Simmy.Latency public class InjectLatencyPolicy : MonkeyPolicy { private readonly Func _latencyProvider; + private readonly Action _beforeInjectCallback; [Obsolete] internal InjectLatencyPolicy( @@ -25,6 +26,7 @@ internal InjectLatencyPolicy(InjectLatencyOptions options) : base(options.InjectionRate, options.Enabled) { _latencyProvider = options.LatencyInternal ?? throw new ArgumentNullException(nameof(options.LatencyInternal)); + _beforeInjectCallback = options.BeforeInjectCallback; } /// @@ -43,7 +45,8 @@ protected override TResult Implementation(Func(Func : MonkeyPolicy { private readonly Func _latencyProvider; + private readonly Action _beforeInjectCallback; [Obsolete] internal InjectLatencyPolicy( @@ -69,6 +73,7 @@ internal InjectLatencyPolicy(InjectLatencyOptions options) : base(options.InjectionRate, options.Enabled) { _latencyProvider = options.LatencyInternal ?? throw new ArgumentNullException(nameof(options.LatencyInternal)); + _beforeInjectCallback = options.BeforeInjectCallback; } /// @@ -87,7 +92,8 @@ protected override TResult Implementation(Func( CancellationToken cancellationToken, Action injectedBehaviour, Func injectionRate, - Func enabled) + Func enabled, + Action beforeInjectCallback) { if (ShouldInject(context, cancellationToken, injectionRate, enabled)) { + if (beforeInjectCallback != null) + { + beforeInjectCallback(context, cancellationToken); + } injectedBehaviour(context, cancellationToken); } @@ -52,7 +57,8 @@ internal static TResult InjectExceptionImplementation( CancellationToken cancellationToken, Func injectedException, Func injectionRate, - Func enabled) + Func enabled, + Action beforeInjectCallback) { if (ShouldInject(context, cancellationToken, injectionRate, enabled)) { @@ -63,6 +69,10 @@ internal static TResult InjectExceptionImplementation( if (exception != null) { + if (beforeInjectCallback != null) + { + beforeInjectCallback(context, cancellationToken); + } throw exception; } } @@ -76,10 +86,15 @@ internal static TResult InjectResultImplementation( CancellationToken cancellationToken, Func injectedResult, Func injectionRate, - Func enabled) + Func enabled, + Action beforeInjectCallback) { if (ShouldInject(context, cancellationToken, injectionRate, enabled)) { + if (beforeInjectCallback != null) + { + beforeInjectCallback(context, cancellationToken); + } return injectedResult(context, cancellationToken); } diff --git a/src/Polly.Contrib.Simmy/Outcomes/AsyncInjectOutcomePolicy.cs b/src/Polly.Contrib.Simmy/Outcomes/AsyncInjectOutcomePolicy.cs index cb07314..8f90e91 100644 --- a/src/Polly.Contrib.Simmy/Outcomes/AsyncInjectOutcomePolicy.cs +++ b/src/Polly.Contrib.Simmy/Outcomes/AsyncInjectOutcomePolicy.cs @@ -11,6 +11,7 @@ namespace Polly.Contrib.Simmy.Outcomes public class AsyncInjectOutcomePolicy : AsyncMonkeyPolicy { private readonly Func> _faultProvider; + private readonly Func _beforeInjectCallback; [Obsolete] internal AsyncInjectOutcomePolicy(Func> faultProvider, Func> injectionRate, Func> enabled) @@ -23,6 +24,7 @@ internal AsyncInjectOutcomePolicy(InjectOutcomeAsyncOptions options) : base(options.InjectionRate, options.Enabled) { _faultProvider = options.Outcome ?? throw new ArgumentNullException(nameof(options.Outcome)); + _beforeInjectCallback = options.BeforeInjectCallback; } /// @@ -36,6 +38,7 @@ protected override Task ImplementationAsync(Func : AsyncMonkeyPolicy { private readonly Func> _faultProvider; private readonly Func> _resultProvider; + private readonly Func _beforeInjectCallback; [Obsolete] internal AsyncInjectOutcomePolicy(Func> faultProvider, Func> injectionRate, Func> enabled) @@ -66,12 +70,14 @@ internal AsyncInjectOutcomePolicy(InjectOutcomeAsyncOptions options) : base(options.InjectionRate, options.Enabled) { _faultProvider = options.Outcome ?? throw new ArgumentNullException(nameof(options.Outcome)); + _beforeInjectCallback = options.BeforeInjectCallback; } internal AsyncInjectOutcomePolicy(InjectOutcomeAsyncOptions options) : base(options.InjectionRate, options.Enabled) { _resultProvider = options.Outcome ?? throw new ArgumentNullException(nameof(options.Outcome)); + _beforeInjectCallback = options.BeforeInjectCallback; } /// @@ -87,6 +93,7 @@ protected override async Task ImplementationAsync(Func ImplementationAsync(Func _faultProvider; + private readonly Action _beforeInjectCallback; [Obsolete] internal InjectOutcomePolicy(Func faultProvider, Func injectionRate, Func enabled) @@ -22,6 +23,7 @@ internal InjectOutcomePolicy(InjectOutcomeOptions options) : base(options.InjectionRate, options.Enabled) { _faultProvider = options.OutcomeInternal ?? throw new ArgumentNullException(nameof(options.OutcomeInternal)); + _beforeInjectCallback = options.BeforeInjectCallback; } /// @@ -33,7 +35,8 @@ protected override TResult Implementation(Func : MonkeyPolicy { private readonly Func _faultProvider; private readonly Func _resultProvider; + private readonly Action _beforeInjectCallback; [Obsolete] internal InjectOutcomePolicy(Func faultProvider, Func injectionRate, Func enabled) @@ -63,12 +67,14 @@ internal InjectOutcomePolicy(InjectOutcomeOptions options) : base(options.InjectionRate, options.Enabled) { _faultProvider = options.OutcomeInternal ?? throw new ArgumentNullException(nameof(options.OutcomeInternal)); + _beforeInjectCallback = options.BeforeInjectCallback; } internal InjectOutcomePolicy(InjectOutcomeOptions options) : base(options.InjectionRate, options.Enabled) { _resultProvider = options.OutcomeInternal ?? throw new ArgumentNullException(nameof(options.OutcomeInternal)); + _beforeInjectCallback = options.BeforeInjectCallback; } /// @@ -82,7 +88,8 @@ protected override TResult Implementation(Func