From 0f5ff2b50dbdb3dc27a58fbda1ed970a02943860 Mon Sep 17 00:00:00 2001 From: peter-csala Date: Tue, 23 Jan 2024 12:13:01 +0100 Subject: [PATCH 1/3] Rename BehaviorAction to BehaviorGenerator --- docs/chaos/behavior.md | 8 ++--- src/Polly.Core/PublicAPI.Unshipped.txt | 12 +++---- ...ments.cs => BehaviorGeneratorArguments.cs} | 6 ++-- .../ChaosBehaviorPipelineBuilderExtensions.cs | 2 +- .../Simmy/Behavior/ChaosBehaviorStrategy.cs | 4 +-- .../Behavior/ChaosBehaviorStrategyOptions.cs | 2 +- src/Snippets/Docs/Chaos.Behavior.cs | 6 ++-- ....cs => BehaviorGeneratorArgumentsTests.cs} | 4 +-- ...sBehaviorPipelineBuilderExtensionsTests.cs | 2 +- .../ChaosBehaviorStrategyOptionsTests.cs | 4 +-- .../Behavior/ChaosBehaviorStrategyTests.cs | 32 +++++++++---------- 11 files changed, 41 insertions(+), 41 deletions(-) rename src/Polly.Core/Simmy/Behavior/{BehaviorActionArguments.cs => BehaviorGeneratorArguments.cs} (69%) rename test/Polly.Core.Tests/Simmy/Behavior/{BehaviorActionArgumentsTests.cs => BehaviorGeneratorArgumentsTests.cs} (56%) diff --git a/docs/chaos/behavior.md b/docs/chaos/behavior.md index 78f012a3775..661957e902b 100644 --- a/docs/chaos/behavior.md +++ b/docs/chaos/behavior.md @@ -20,7 +20,7 @@ The behavior chaos strategy is designed to inject custom behaviors into system o // To use a custom delegated for injected behavior var optionsWithBehaviorGenerator = new ChaosBehaviorStrategyOptions { - BehaviorAction = static args => RestartRedisAsync(args.Context.CancellationToken), + BehaviorGenerator = static args => RestartRedisAsync(args.Context.CancellationToken), Enabled = true, InjectionRate = 0.05 }; @@ -28,7 +28,7 @@ var optionsWithBehaviorGenerator = new ChaosBehaviorStrategyOptions // To get notifications when a behavior is injected var optionsOnBehaviorInjected = new ChaosBehaviorStrategyOptions { - BehaviorAction = static args => RestartRedisAsync(args.Context.CancellationToken), + BehaviorGenerator = static args => RestartRedisAsync(args.Context.CancellationToken), Enabled = true, InjectionRate = 0.05, OnBehaviorInjected = static args => @@ -62,7 +62,7 @@ var pipeline = new ResiliencePipelineBuilder() }) .AddChaosBehavior(new ChaosBehaviorStrategyOptions // Chaos strategies are usually placed as the last ones in the pipeline { - BehaviorAction = static args => RestartRedisAsync(args.Context.CancellationToken), + BehaviorGenerator = static args => RestartRedisAsync(args.Context.CancellationToken), Enabled = true, InjectionRate = 0.05 }) @@ -75,7 +75,7 @@ var pipeline = new ResiliencePipelineBuilder() | Property | Default Value | Description | |----------------------|---------------|------------------------------------------------| | `OnBehaviorInjected` | `null` | Action executed when the behavior is injected. | -| `BehaviorAction` | `null` | Custom behavior to be injected. | +| `BehaviorGenerator` | `null` | Custom behavior to be injected. | ## Diagrams diff --git a/src/Polly.Core/PublicAPI.Unshipped.txt b/src/Polly.Core/PublicAPI.Unshipped.txt index 9496b0ddbab..13b4e3d6a63 100644 --- a/src/Polly.Core/PublicAPI.Unshipped.txt +++ b/src/Polly.Core/PublicAPI.Unshipped.txt @@ -1,13 +1,13 @@ #nullable enable Polly.CircuitBreaker.BreakDurationGeneratorArguments.BreakDurationGeneratorArguments(double failureRate, int failureCount, Polly.ResilienceContext! context, int halfOpenAttempts) -> void Polly.CircuitBreaker.BreakDurationGeneratorArguments.HalfOpenAttempts.get -> int -Polly.Simmy.Behavior.BehaviorActionArguments -Polly.Simmy.Behavior.BehaviorActionArguments.BehaviorActionArguments() -> void -Polly.Simmy.Behavior.BehaviorActionArguments.BehaviorActionArguments(Polly.ResilienceContext! context) -> void -Polly.Simmy.Behavior.BehaviorActionArguments.Context.get -> Polly.ResilienceContext! +Polly.Simmy.Behavior.BehaviorGeneratorArguments +Polly.Simmy.Behavior.BehaviorGeneratorArguments.BehaviorGeneratorArguments() -> void +Polly.Simmy.Behavior.BehaviorGeneratorArguments.BehaviorGeneratorArguments(Polly.ResilienceContext! context) -> void +Polly.Simmy.Behavior.BehaviorGeneratorArguments.Context.get -> Polly.ResilienceContext! Polly.Simmy.Behavior.ChaosBehaviorStrategyOptions -Polly.Simmy.Behavior.ChaosBehaviorStrategyOptions.BehaviorAction.get -> System.Func? -Polly.Simmy.Behavior.ChaosBehaviorStrategyOptions.BehaviorAction.set -> void +Polly.Simmy.Behavior.ChaosBehaviorStrategyOptions.BehaviorGenerator.get -> System.Func? +Polly.Simmy.Behavior.ChaosBehaviorStrategyOptions.BehaviorGenerator.set -> void Polly.Simmy.Behavior.ChaosBehaviorStrategyOptions.ChaosBehaviorStrategyOptions() -> void Polly.Simmy.Behavior.ChaosBehaviorStrategyOptions.OnBehaviorInjected.get -> System.Func? Polly.Simmy.Behavior.ChaosBehaviorStrategyOptions.OnBehaviorInjected.set -> void diff --git a/src/Polly.Core/Simmy/Behavior/BehaviorActionArguments.cs b/src/Polly.Core/Simmy/Behavior/BehaviorGeneratorArguments.cs similarity index 69% rename from src/Polly.Core/Simmy/Behavior/BehaviorActionArguments.cs rename to src/Polly.Core/Simmy/Behavior/BehaviorGeneratorArguments.cs index 2df7cdd1724..a8b9b01a38c 100644 --- a/src/Polly.Core/Simmy/Behavior/BehaviorActionArguments.cs +++ b/src/Polly.Core/Simmy/Behavior/BehaviorGeneratorArguments.cs @@ -5,13 +5,13 @@ /// /// Arguments used by the behavior chaos strategy to execute a user's delegate custom action. /// -public readonly struct BehaviorActionArguments +public readonly struct BehaviorGeneratorArguments { /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The context associated with the execution of a user-provided callback. - public BehaviorActionArguments(ResilienceContext context) => Context = context; + public BehaviorGeneratorArguments(ResilienceContext context) => Context = context; /// /// Gets the ResilienceContext instance. diff --git a/src/Polly.Core/Simmy/Behavior/ChaosBehaviorPipelineBuilderExtensions.cs b/src/Polly.Core/Simmy/Behavior/ChaosBehaviorPipelineBuilderExtensions.cs index 35eff9cba36..1a0723e3e7b 100644 --- a/src/Polly.Core/Simmy/Behavior/ChaosBehaviorPipelineBuilderExtensions.cs +++ b/src/Polly.Core/Simmy/Behavior/ChaosBehaviorPipelineBuilderExtensions.cs @@ -28,7 +28,7 @@ public static TBuilder AddChaosBehavior(this TBuilder builder, double { Enabled = true, InjectionRate = injectionRate, - BehaviorAction = args => behavior(args.Context.CancellationToken) + BehaviorGenerator = args => behavior(args.Context.CancellationToken) }); } diff --git a/src/Polly.Core/Simmy/Behavior/ChaosBehaviorStrategy.cs b/src/Polly.Core/Simmy/Behavior/ChaosBehaviorStrategy.cs index f8808d0f84b..9a22a678820 100644 --- a/src/Polly.Core/Simmy/Behavior/ChaosBehaviorStrategy.cs +++ b/src/Polly.Core/Simmy/Behavior/ChaosBehaviorStrategy.cs @@ -13,12 +13,12 @@ public ChaosBehaviorStrategy( { _telemetry = telemetry; OnBehaviorInjected = options.OnBehaviorInjected; - Behavior = options.BehaviorAction!; + Behavior = options.BehaviorGenerator!; } public Func? OnBehaviorInjected { get; } - public Func Behavior { get; } + public Func Behavior { get; } protected internal override async ValueTask> ExecuteCore( Func>> callback, diff --git a/src/Polly.Core/Simmy/Behavior/ChaosBehaviorStrategyOptions.cs b/src/Polly.Core/Simmy/Behavior/ChaosBehaviorStrategyOptions.cs index 1e32c1b89c8..9ba5108a18f 100644 --- a/src/Polly.Core/Simmy/Behavior/ChaosBehaviorStrategyOptions.cs +++ b/src/Polly.Core/Simmy/Behavior/ChaosBehaviorStrategyOptions.cs @@ -27,5 +27,5 @@ public class ChaosBehaviorStrategyOptions : ChaosStrategyOptions /// Defaults to . /// [Required] - public Func? BehaviorAction { get; set; } + public Func? BehaviorGenerator { get; set; } } diff --git a/src/Snippets/Docs/Chaos.Behavior.cs b/src/Snippets/Docs/Chaos.Behavior.cs index 91088a51fc7..2f7af023439 100644 --- a/src/Snippets/Docs/Chaos.Behavior.cs +++ b/src/Snippets/Docs/Chaos.Behavior.cs @@ -13,7 +13,7 @@ public static void BehaviorUsage() // To use a custom delegated for injected behavior var optionsWithBehaviorGenerator = new ChaosBehaviorStrategyOptions { - BehaviorAction = static args => RestartRedisAsync(args.Context.CancellationToken), + BehaviorGenerator = static args => RestartRedisAsync(args.Context.CancellationToken), Enabled = true, InjectionRate = 0.05 }; @@ -21,7 +21,7 @@ public static void BehaviorUsage() // To get notifications when a behavior is injected var optionsOnBehaviorInjected = new ChaosBehaviorStrategyOptions { - BehaviorAction = static args => RestartRedisAsync(args.Context.CancellationToken), + BehaviorGenerator = static args => RestartRedisAsync(args.Context.CancellationToken), Enabled = true, InjectionRate = 0.05, OnBehaviorInjected = static args => @@ -51,7 +51,7 @@ public static void BehaviorUsage() }) .AddChaosBehavior(new ChaosBehaviorStrategyOptions // Chaos strategies are usually placed as the last ones in the pipeline { - BehaviorAction = static args => RestartRedisAsync(args.Context.CancellationToken), + BehaviorGenerator = static args => RestartRedisAsync(args.Context.CancellationToken), Enabled = true, InjectionRate = 0.05 }) diff --git a/test/Polly.Core.Tests/Simmy/Behavior/BehaviorActionArgumentsTests.cs b/test/Polly.Core.Tests/Simmy/Behavior/BehaviorGeneratorArgumentsTests.cs similarity index 56% rename from test/Polly.Core.Tests/Simmy/Behavior/BehaviorActionArgumentsTests.cs rename to test/Polly.Core.Tests/Simmy/Behavior/BehaviorGeneratorArgumentsTests.cs index d357abd4377..687491b82ab 100644 --- a/test/Polly.Core.Tests/Simmy/Behavior/BehaviorActionArgumentsTests.cs +++ b/test/Polly.Core.Tests/Simmy/Behavior/BehaviorGeneratorArgumentsTests.cs @@ -2,12 +2,12 @@ namespace Polly.Core.Tests.Simmy.Behavior; -public class BehaviorActionArgumentsTests +public class BehaviorGeneratorArgumentsTests { [Fact] public void Ctor_Ok() { - var args = new BehaviorActionArguments(ResilienceContextPool.Shared.Get()); + var args = new BehaviorGeneratorArguments(ResilienceContextPool.Shared.Get()); args.Context.Should().NotBeNull(); } } diff --git a/test/Polly.Core.Tests/Simmy/Behavior/ChaosBehaviorPipelineBuilderExtensionsTests.cs b/test/Polly.Core.Tests/Simmy/Behavior/ChaosBehaviorPipelineBuilderExtensionsTests.cs index 6c81201634d..a90fd463ee1 100644 --- a/test/Polly.Core.Tests/Simmy/Behavior/ChaosBehaviorPipelineBuilderExtensionsTests.cs +++ b/test/Polly.Core.Tests/Simmy/Behavior/ChaosBehaviorPipelineBuilderExtensionsTests.cs @@ -56,7 +56,7 @@ public void AddBehavior_Options_Ok() { Enabled = true, InjectionRate = 1, - BehaviorAction = (_) => default + BehaviorGenerator = (_) => default }) .Build(); diff --git a/test/Polly.Core.Tests/Simmy/Behavior/ChaosBehaviorStrategyOptionsTests.cs b/test/Polly.Core.Tests/Simmy/Behavior/ChaosBehaviorStrategyOptionsTests.cs index 00a87287bf8..7c3188e0244 100644 --- a/test/Polly.Core.Tests/Simmy/Behavior/ChaosBehaviorStrategyOptionsTests.cs +++ b/test/Polly.Core.Tests/Simmy/Behavior/ChaosBehaviorStrategyOptionsTests.cs @@ -16,7 +16,7 @@ public void Ctor_Ok() sut.EnabledGenerator.Should().BeNull(); sut.InjectionRate.Should().Be(ChaosStrategyConstants.DefaultInjectionRate); sut.InjectionRateGenerator.Should().BeNull(); - sut.BehaviorAction.Should().BeNull(); + sut.BehaviorGenerator.Should().BeNull(); sut.OnBehaviorInjected.Should().BeNull(); } @@ -33,7 +33,7 @@ public void InvalidOptions() Invalid Options Validation Errors: - The BehaviorAction field is required. + The BehaviorGenerator field is required. """); } } diff --git a/test/Polly.Core.Tests/Simmy/Behavior/ChaosBehaviorStrategyTests.cs b/test/Polly.Core.Tests/Simmy/Behavior/ChaosBehaviorStrategyTests.cs index 983e8434024..cc1195eb43a 100644 --- a/test/Polly.Core.Tests/Simmy/Behavior/ChaosBehaviorStrategyTests.cs +++ b/test/Polly.Core.Tests/Simmy/Behavior/ChaosBehaviorStrategyTests.cs @@ -8,7 +8,7 @@ public class ChaosBehaviorStrategyTests private readonly ResilienceStrategyTelemetry _telemetry; private readonly ChaosBehaviorStrategyOptions _options; private readonly List> _args = []; - private bool _behaviorActionExecuted; + private bool _behaviorGeneratorExecuted; private bool _onBehaviorInjectedExecuted; private bool _userDelegateExecuted; @@ -17,7 +17,7 @@ public ChaosBehaviorStrategyTests() _telemetry = TestUtilities.CreateResilienceTelemetry(arg => _args.Add(arg)); _options = new(); _userDelegateExecuted = false; - _behaviorActionExecuted = false; + _behaviorGeneratorExecuted = false; _onBehaviorInjectedExecuted = false; } @@ -27,13 +27,13 @@ public void Given_not_enabled_should_not_inject_behavior() _options.InjectionRate = 0.6; _options.Enabled = false; _options.Randomizer = () => 0.5; - _options.BehaviorAction = (_) => { _behaviorActionExecuted = true; return default; }; + _options.BehaviorGenerator = (_) => { _behaviorGeneratorExecuted = true; return default; }; var sut = CreateSut(); sut.Execute(() => { _userDelegateExecuted = true; }); _userDelegateExecuted.Should().BeTrue(); - _behaviorActionExecuted.Should().BeFalse(); + _behaviorGeneratorExecuted.Should().BeFalse(); } [Fact] @@ -42,13 +42,13 @@ public async Task Given_enabled_and_randomly_within_threshold_should_inject_beha _options.InjectionRate = 0.6; _options.Enabled = true; _options.Randomizer = () => 0.5; - _options.BehaviorAction = (_) => { _behaviorActionExecuted = true; return default; }; + _options.BehaviorGenerator = (_) => { _behaviorGeneratorExecuted = true; return default; }; var sut = CreateSut(); await sut.ExecuteAsync((_) => { _userDelegateExecuted = true; return default; }); _userDelegateExecuted.Should().BeTrue(); - _behaviorActionExecuted.Should().BeTrue(); + _behaviorGeneratorExecuted.Should().BeTrue(); _onBehaviorInjectedExecuted.Should().BeFalse(); } @@ -58,7 +58,7 @@ public async Task Given_enabled_and_randomly_within_threshold_ensure_on_behavior _options.InjectionRate = 0.6; _options.Enabled = true; _options.Randomizer = () => 0.5; - _options.BehaviorAction = (_) => { _behaviorActionExecuted = true; return default; }; + _options.BehaviorGenerator = (_) => { _behaviorGeneratorExecuted = true; return default; }; _options.OnBehaviorInjected = args => { args.Context.Should().NotBeNull(); @@ -72,7 +72,7 @@ public async Task Given_enabled_and_randomly_within_threshold_ensure_on_behavior _onBehaviorInjectedExecuted.Should().BeTrue(); _userDelegateExecuted.Should().BeTrue(); - _behaviorActionExecuted.Should().BeTrue(); + _behaviorGeneratorExecuted.Should().BeTrue(); _args.Should().HaveCount(1); _args[0].Arguments.Should().BeOfType(); } @@ -83,13 +83,13 @@ public async Task Given_enabled_and_randomly_not_within_threshold_should_not_inj _options.InjectionRate = 0.4; _options.Enabled = false; _options.Randomizer = () => 0.5; - _options.BehaviorAction = (_) => { _behaviorActionExecuted = true; return default; }; + _options.BehaviorGenerator = (_) => { _behaviorGeneratorExecuted = true; return default; }; var sut = CreateSut(); await sut.ExecuteAsync((_) => { _userDelegateExecuted = true; return default; }); _userDelegateExecuted.Should().BeTrue(); - _behaviorActionExecuted.Should().BeFalse(); + _behaviorGeneratorExecuted.Should().BeFalse(); _onBehaviorInjectedExecuted.Should().BeFalse(); } @@ -99,10 +99,10 @@ public async Task Should_inject_behavior_before_executing_user_delegate() _options.InjectionRate = 0.6; _options.Enabled = true; _options.Randomizer = () => 0.5; - _options.BehaviorAction = (_) => + _options.BehaviorGenerator = (_) => { _userDelegateExecuted.Should().BeFalse(); // Not yet executed at the time the injected behavior runs. - _behaviorActionExecuted = true; + _behaviorGeneratorExecuted = true; return default; }; @@ -110,7 +110,7 @@ public async Task Should_inject_behavior_before_executing_user_delegate() await sut.ExecuteAsync((_) => { _userDelegateExecuted = true; return default; }); _userDelegateExecuted.Should().BeTrue(); - _behaviorActionExecuted.Should().BeTrue(); + _behaviorGeneratorExecuted.Should().BeTrue(); _onBehaviorInjectedExecuted.Should().BeFalse(); } @@ -121,10 +121,10 @@ public async Task Should_not_execute_user_delegate_when_it_was_cancelled_running _options.InjectionRate = 0.6; _options.Enabled = true; _options.Randomizer = () => 0.5; - _options.BehaviorAction = (_) => + _options.BehaviorGenerator = (_) => { cts.Cancel(); - _behaviorActionExecuted = true; + _behaviorGeneratorExecuted = true; return default; }; @@ -134,7 +134,7 @@ public async Task Should_not_execute_user_delegate_when_it_was_cancelled_running .ThrowAsync(); _userDelegateExecuted.Should().BeFalse(); - _behaviorActionExecuted.Should().BeTrue(); + _behaviorGeneratorExecuted.Should().BeTrue(); _onBehaviorInjectedExecuted.Should().BeFalse(); } From aa0c10254cc6531af2958e839e0a0dfb2fd5ae4f Mon Sep 17 00:00:00 2001 From: peter-csala Date: Tue, 23 Jan 2024 12:18:38 +0100 Subject: [PATCH 2/3] Added sample for anti-pattern --- docs/chaos/behavior.md | 22 ++++++++++++++++++++++ src/Snippets/Docs/Chaos.Behavior.cs | 25 +++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/docs/chaos/behavior.md b/docs/chaos/behavior.md index 661957e902b..e62cd5b5c39 100644 --- a/docs/chaos/behavior.md +++ b/docs/chaos/behavior.md @@ -128,6 +128,28 @@ sequenceDiagram Use behavior strategies to inject delays. + +```cs +var pipeline = new ResiliencePipelineBuilder() + .AddChaosBehavior(new ChaosBehaviorStrategyOptions + { + BehaviorGenerator = static args => Task.Delay(TimeSpan.FromSeconds(7), args.Context.CancellationToken), + }) + .Build(); +``` + + ✅ DO Use the latency chaos instead as the [`ChaosLatencyStrategy`](latency.md) already correctly handles synchronous/asynchronous delay executions, cancellations, etc. + + +```cs +var pipeline = new ResiliencePipelineBuilder() + .AddChaosLatency(new ChaosLatencyStrategyOptions + { + Latency = TimeSpan.FromSeconds(7), + }) + .Build(); +``` + diff --git a/src/Snippets/Docs/Chaos.Behavior.cs b/src/Snippets/Docs/Chaos.Behavior.cs index 2f7af023439..d1e6e56c555 100644 --- a/src/Snippets/Docs/Chaos.Behavior.cs +++ b/src/Snippets/Docs/Chaos.Behavior.cs @@ -58,6 +58,31 @@ public static void BehaviorUsage() .Build(); #endregion } + + public static void AntiPattern_InjectDelay() + { + #region chaos-behavior-anti-pattern-inject-delay + var pipeline = new ResiliencePipelineBuilder() + .AddChaosBehavior(new ChaosBehaviorStrategyOptions + { + BehaviorGenerator = static args => Task.Delay(TimeSpan.FromSeconds(7), args.Context.CancellationToken), + }) + .Build(); + + #endregion + } + + public static void Pattern_InjectDelay() + { + #region chaos-behavior-pattern-inject-delay + var pipeline = new ResiliencePipelineBuilder() + .AddChaosLatency(new ChaosLatencyStrategyOptions + { + Latency = TimeSpan.FromSeconds(7), + }) + .Build(); + #endregion + } } internal class RedisConnectionException : Exception From e9e48a5c52bba0bcfd142e5544b29ea6889fbc4f Mon Sep 17 00:00:00 2001 From: peter-csala Date: Tue, 23 Jan 2024 13:16:02 +0100 Subject: [PATCH 3/3] Fix build --- docs/chaos/behavior.md | 5 ++++- src/Snippets/Docs/Chaos.Behavior.cs | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/chaos/behavior.md b/docs/chaos/behavior.md index e62cd5b5c39..b931cf7d79b 100644 --- a/docs/chaos/behavior.md +++ b/docs/chaos/behavior.md @@ -133,7 +133,10 @@ Use behavior strategies to inject delays. var pipeline = new ResiliencePipelineBuilder() .AddChaosBehavior(new ChaosBehaviorStrategyOptions { - BehaviorGenerator = static args => Task.Delay(TimeSpan.FromSeconds(7), args.Context.CancellationToken), + BehaviorGenerator = static async args => + { + await Task.Delay(TimeSpan.FromSeconds(7), args.Context.CancellationToken); + } }) .Build(); ``` diff --git a/src/Snippets/Docs/Chaos.Behavior.cs b/src/Snippets/Docs/Chaos.Behavior.cs index d1e6e56c555..3c5d2a2bd44 100644 --- a/src/Snippets/Docs/Chaos.Behavior.cs +++ b/src/Snippets/Docs/Chaos.Behavior.cs @@ -2,6 +2,7 @@ using Polly.Retry; using Polly.Simmy; using Polly.Simmy.Behavior; +using Polly.Simmy.Latency; namespace Snippets.Docs; @@ -65,7 +66,10 @@ public static void AntiPattern_InjectDelay() var pipeline = new ResiliencePipelineBuilder() .AddChaosBehavior(new ChaosBehaviorStrategyOptions { - BehaviorGenerator = static args => Task.Delay(TimeSpan.FromSeconds(7), args.Context.CancellationToken), + BehaviorGenerator = static async args => + { + await Task.Delay(TimeSpan.FromSeconds(7), args.Context.CancellationToken); + } }) .Build();