From 3ec4b7ca9533e119e97d76d9d29e5157ce6141be Mon Sep 17 00:00:00 2001 From: Martin Tomka Date: Thu, 27 Jul 2023 20:29:13 +0200 Subject: [PATCH 1/2] Drop simple circuit breaker --- .../Utils/Helper.CircuitBreaker.cs | 10 +- .../Utils/Helper.MultipleStrategies.cs | 8 +- ...edCircuitBreakerStrategyOptions.TResult.cs | 55 ------- .../AdvancedCircuitBreakerStrategyOptions.cs | 6 - .../CircuitBreaker/CircuitBreakerConstants.cs | 4 +- ...akerResilienceStrategyBuilderExtensions.cs | 85 ++--------- .../CircuitBreakerStateProvider.cs | 2 +- .../CircuitBreakerStrategyOptions.TResult.cs | 137 ++++++++++++++++++ .../CircuitBreakerStrategyOptions.cs | 99 +------------ .../Controller/AdvancedCircuitBehavior.cs | 8 +- .../ConsecutiveFailuresCircuitBehavior.cs | 37 ----- ...leCircuitBreakerStrategyOptions.TResult.cs | 31 ---- .../SimpleCircuitBreakerStrategyOptions.cs | 6 - src/Polly.Core/PublicAPI.Unshipped.txt | 31 ++-- ...Tests.cs => CircuitBreakerOptionsTests.cs} | 20 +-- ...itBreakerResilienceStrategyBuilderTests.cs | 87 ++--------- .../CircuitBreakerResilienceStrategyTests.cs | 4 +- .../AdvancedCircuitBehaviorTests.cs | 2 +- .../Controller/CircuitStateControllerTests.cs | 2 +- ...ConsecutiveFailuresCircuitBehaviorTests.cs | 49 ------- .../SimpleCircuitBreakerOptionsTests.cs | 88 ----------- ...uesTests.CircuitBreakerStateSharing_959.cs | 6 +- .../Polly.Core.Tests/PredicateBuilderTests.cs | 2 +- ...s.OnCircuitBreakWithServiceProvider_796.cs | 4 +- .../IssuesTests.StrategiesPerEndpoint_1365.cs | 2 +- .../ResilienceStrategyExtensionsTests.cs | 4 +- 26 files changed, 207 insertions(+), 582 deletions(-) delete mode 100644 src/Polly.Core/CircuitBreaker/AdvancedCircuitBreakerStrategyOptions.TResult.cs delete mode 100644 src/Polly.Core/CircuitBreaker/AdvancedCircuitBreakerStrategyOptions.cs create mode 100644 src/Polly.Core/CircuitBreaker/CircuitBreakerStrategyOptions.TResult.cs delete mode 100644 src/Polly.Core/CircuitBreaker/Controller/ConsecutiveFailuresCircuitBehavior.cs delete mode 100644 src/Polly.Core/CircuitBreaker/SimpleCircuitBreakerStrategyOptions.TResult.cs delete mode 100644 src/Polly.Core/CircuitBreaker/SimpleCircuitBreakerStrategyOptions.cs rename test/Polly.Core.Tests/CircuitBreaker/{AdvancedCircuitBreakerOptionsTests.cs => CircuitBreakerOptionsTests.cs} (85%) delete mode 100644 test/Polly.Core.Tests/CircuitBreaker/Controller/ConsecutiveFailuresCircuitBehaviorTests.cs delete mode 100644 test/Polly.Core.Tests/CircuitBreaker/SimpleCircuitBreakerOptionsTests.cs diff --git a/bench/Polly.Core.Benchmarks/Utils/Helper.CircuitBreaker.cs b/bench/Polly.Core.Benchmarks/Utils/Helper.CircuitBreaker.cs index 27edadbfda..411aa8b48d 100644 --- a/bench/Polly.Core.Benchmarks/Utils/Helper.CircuitBreaker.cs +++ b/bench/Polly.Core.Benchmarks/Utils/Helper.CircuitBreaker.cs @@ -5,7 +5,7 @@ internal static partial class Helper public static object CreateOpenedCircuitBreaker(PollyVersion version, bool handleOutcome) { var manualControl = new CircuitBreakerManualControl(); - var options = new AdvancedCircuitBreakerStrategyOptions + var options = new CircuitBreakerStrategyOptions { ShouldHandle = _ => PredicateResult.True, ManualControl = manualControl, @@ -20,13 +20,13 @@ public static object CreateOpenedCircuitBreaker(PollyVersion version, bool handl builder.AddStrategy(new OutcomeHandlingStrategy()); } - var strategy = builder.AddAdvancedCircuitBreaker(options).Build(); + var strategy = builder.AddCircuitBreaker(options).Build(); manualControl.IsolateAsync().GetAwaiter().GetResult(); return strategy; } else { - var policy = Policy.HandleResult(r => true).AdvancedCircuitBreakerAsync(options.FailureThreshold, options.SamplingDuration, options.MinimumThroughput, options.BreakDuration); + var policy = Policy.HandleResult(r => true).AdvancedCircuitBreakerAsync(options.FailureRatio, options.SamplingDuration, options.MinimumThroughput, options.BreakDuration); policy.Isolate(); return policy; } @@ -46,9 +46,9 @@ public static object CreateCircuitBreaker(PollyVersion technology) PollyVersion.V8 => CreateStrategy(builder => { - builder.AddAdvancedCircuitBreaker(new AdvancedCircuitBreakerStrategyOptions + builder.AddCircuitBreaker(new CircuitBreakerStrategyOptions { - FailureThreshold = 0.5, + FailureRatio = 0.5, SamplingDuration = TimeSpan.FromSeconds(30), MinimumThroughput = 10, BreakDuration = TimeSpan.FromSeconds(5), diff --git a/bench/Polly.Core.Benchmarks/Utils/Helper.MultipleStrategies.cs b/bench/Polly.Core.Benchmarks/Utils/Helper.MultipleStrategies.cs index 5e2dbc20fe..404f6f2e17 100644 --- a/bench/Polly.Core.Benchmarks/Utils/Helper.MultipleStrategies.cs +++ b/bench/Polly.Core.Benchmarks/Utils/Helper.MultipleStrategies.cs @@ -35,9 +35,9 @@ internal static partial class Helper } }) .AddTimeout(TimeSpan.FromSeconds(1)) - .AddAdvancedCircuitBreaker(new() + .AddCircuitBreaker(new() { - FailureThreshold = 0.5, + FailureRatio = 0.5, SamplingDuration = TimeSpan.FromSeconds(30), MinimumThroughput = 10, BreakDuration = TimeSpan.FromSeconds(5), @@ -79,9 +79,9 @@ public static ResilienceStrategy CreateNonGenericStrategyPipeline() } }) .AddTimeout(TimeSpan.FromSeconds(1)) - .AddAdvancedCircuitBreaker(new() + .AddCircuitBreaker(new() { - FailureThreshold = 0.5, + FailureRatio = 0.5, SamplingDuration = TimeSpan.FromSeconds(30), MinimumThroughput = 10, BreakDuration = TimeSpan.FromSeconds(5), diff --git a/src/Polly.Core/CircuitBreaker/AdvancedCircuitBreakerStrategyOptions.TResult.cs b/src/Polly.Core/CircuitBreaker/AdvancedCircuitBreakerStrategyOptions.TResult.cs deleted file mode 100644 index b2fccbcf24..0000000000 --- a/src/Polly.Core/CircuitBreaker/AdvancedCircuitBreakerStrategyOptions.TResult.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace Polly.CircuitBreaker; - -/// -/// The options for advanced circuit breaker resilience strategy. -/// -/// The type of result the circuit breaker strategy handles. -/// -/// The circuit will break if, within any time-slice of duration , -/// the proportion of actions resulting in a handled exception exceeds , -/// provided also that the number of actions through the circuit in the time-slice is at least . -/// -/// The circuit will stay broken for the . -/// Any attempt to execute this while the circuit is broken, will immediately throw a containing the exception -/// that broke the circuit. -/// -/// -/// If the first action after the break duration period results in a handled exception, the circuit will break -/// again for another ; if no exception is thrown, the circuit will reset. -/// -/// -public class AdvancedCircuitBreakerStrategyOptions : CircuitBreakerStrategyOptions -{ - /// - /// Gets or sets the failure threshold at which the circuit will break. - /// - /// - /// A number between zero and one (inclusive) e.g. 0.5 represents breaking if 50% or more of actions result in a handled failure. - /// - /// A ratio number higher than 0, up to 1. The default value is 0.1 (i.e. 10%). - [Range(0, 1.0)] - public double FailureThreshold { get; set; } = CircuitBreakerConstants.DefaultAdvancedFailureThreshold; - - /// - /// Gets or sets the minimum throughput: this many actions or more must pass through the circuit in the time-slice, - /// for statistics to be considered significant and the circuit-breaker to come into action. - /// - /// - /// The default value is 0.1 (i.e. 10%). The value must be 2 or greater. - /// - [Range(CircuitBreakerConstants.MinimumValidThroughput, int.MaxValue)] - public int MinimumThroughput { get; set; } = CircuitBreakerConstants.DefaultMinimumThroughput; - -#pragma warning disable IL2026 // Addressed with DynamicDependency on ValidationHelper.Validate method - /// - /// Gets or sets the duration of the sampling over which failure ratios are assessed. - /// - /// - /// The default value is 30 seconds. Value must be greater than 0.5 seconds. - /// - [Range(typeof(TimeSpan), "00:00:00.500", "1.00:00:00")] - public TimeSpan SamplingDuration { get; set; } = CircuitBreakerConstants.DefaultSamplingDuration; -#pragma warning restore IL2026 -} diff --git a/src/Polly.Core/CircuitBreaker/AdvancedCircuitBreakerStrategyOptions.cs b/src/Polly.Core/CircuitBreaker/AdvancedCircuitBreakerStrategyOptions.cs deleted file mode 100644 index 0d2f0bdae7..0000000000 --- a/src/Polly.Core/CircuitBreaker/AdvancedCircuitBreakerStrategyOptions.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Polly.CircuitBreaker; - -/// -public class AdvancedCircuitBreakerStrategyOptions : AdvancedCircuitBreakerStrategyOptions -{ -} diff --git a/src/Polly.Core/CircuitBreaker/CircuitBreakerConstants.cs b/src/Polly.Core/CircuitBreaker/CircuitBreakerConstants.cs index ad9b6b2aab..6b31f0794c 100644 --- a/src/Polly.Core/CircuitBreaker/CircuitBreakerConstants.cs +++ b/src/Polly.Core/CircuitBreaker/CircuitBreakerConstants.cs @@ -8,14 +8,12 @@ internal static class CircuitBreakerConstants public const string OnCircuitOpened = "OnCircuitOpened"; - public const double DefaultAdvancedFailureThreshold = 0.1; + public const double DefaultFailureRatio = 0.1; public const int DefaultMinimumThroughput = 100; public const int MinimumValidThroughput = 2; - public const int DefaultFailureThreshold = 100; - public static readonly TimeSpan DefaultBreakDuration = TimeSpan.FromSeconds(5); public static readonly TimeSpan DefaultSamplingDuration = TimeSpan.FromSeconds(30); diff --git a/src/Polly.Core/CircuitBreaker/CircuitBreakerResilienceStrategyBuilderExtensions.cs b/src/Polly.Core/CircuitBreaker/CircuitBreakerResilienceStrategyBuilderExtensions.cs index be087787f3..3c20a9f228 100644 --- a/src/Polly.Core/CircuitBreaker/CircuitBreakerResilienceStrategyBuilderExtensions.cs +++ b/src/Polly.Core/CircuitBreaker/CircuitBreakerResilienceStrategyBuilderExtensions.cs @@ -11,129 +11,66 @@ namespace Polly; public static class CircuitBreakerResilienceStrategyBuilderExtensions { /// - /// Add advanced circuit breaker strategy to the builder. + /// Add circuit breaker strategy to the builder. /// /// The builder instance. /// The options instance. /// A builder with the circuit breaker strategy added. /// - /// See for more details about the advanced circuit breaker strategy. + /// See for more details about the circuit breaker strategy. /// /// If you are discarding the strategy created by this call make sure to use and dispose the manual control instance when the strategy is no longer used. /// /// /// Thrown when or is . /// Thrown when are invalid. - public static ResilienceStrategyBuilder AddAdvancedCircuitBreaker(this ResilienceStrategyBuilder builder, AdvancedCircuitBreakerStrategyOptions options) + public static ResilienceStrategyBuilder AddCircuitBreaker(this ResilienceStrategyBuilder builder, CircuitBreakerStrategyOptions options) { Guard.NotNull(builder); Guard.NotNull(options); - return builder.AddAdvancedCircuitBreakerCore(options); + return builder.AddCircuitBreakerCore(options); } /// - /// Add advanced circuit breaker strategy to the builder. + /// Add circuit breaker strategy to the builder. /// /// The type of result the circuit breaker strategy handles. /// The builder instance. /// The options instance. /// A builder with the circuit breaker strategy added. /// - /// See for more details about the advanced circuit breaker strategy. + /// See for more details about the circuit breaker strategy. /// /// If you are discarding the strategy created by this call make sure to use and dispose the manual control instance when the strategy is no longer used. /// /// /// Thrown when or is . /// Thrown when are invalid. - public static ResilienceStrategyBuilder AddAdvancedCircuitBreaker(this ResilienceStrategyBuilder builder, AdvancedCircuitBreakerStrategyOptions options) + public static ResilienceStrategyBuilder AddCircuitBreaker(this ResilienceStrategyBuilder builder, CircuitBreakerStrategyOptions options) { Guard.NotNull(builder); Guard.NotNull(options); - return builder.AddAdvancedCircuitBreakerCore(options); - } - - /// - /// Add simple circuit breaker strategy to the builder. - /// - /// The type of result the circuit breaker strategy handles. - /// The builder instance. - /// The options instance. - /// A builder with the circuit breaker strategy added. - /// - /// See for more details about the advanced circuit breaker strategy. - /// - /// If you are discarding the strategy created by this call make sure to use and dispose the manual control instance when the strategy is no longer used. - /// - /// - /// Thrown when or is . - /// Thrown when are invalid. - public static ResilienceStrategyBuilder AddSimpleCircuitBreaker(this ResilienceStrategyBuilder builder, SimpleCircuitBreakerStrategyOptions options) - { - Guard.NotNull(builder); - Guard.NotNull(options); - - return builder.AddSimpleCircuitBreakerCore(options); - } - - /// - /// Add simple circuit breaker strategy to the builder. - /// - /// The builder instance. - /// The options instance. - /// A builder with the circuit breaker strategy added. - /// - /// See for more details about the advanced circuit breaker strategy. - /// - /// If you are discarding the strategy created by this call make sure to use and dispose the manual control instance when the strategy is no longer used. - /// - /// - /// Thrown when or is . - /// Thrown when are invalid. - public static ResilienceStrategyBuilder AddSimpleCircuitBreaker(this ResilienceStrategyBuilder builder, SimpleCircuitBreakerStrategyOptions options) - { - Guard.NotNull(builder); - Guard.NotNull(options); - - return builder.AddSimpleCircuitBreakerCore(options); + return builder.AddCircuitBreakerCore(options); } [UnconditionalSuppressMessage( "Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "All options members preserved.")] - private static TBuilder AddAdvancedCircuitBreakerCore(this TBuilder builder, AdvancedCircuitBreakerStrategyOptions options) + private static TBuilder AddCircuitBreakerCore(this TBuilder builder, CircuitBreakerStrategyOptions options) where TBuilder : ResilienceStrategyBuilderBase { return builder.AddStrategy( context => { var behavior = new AdvancedCircuitBehavior( - options.FailureThreshold, + options.FailureRatio, options.MinimumThroughput, HealthMetrics.Create(options.SamplingDuration, context.TimeProvider)); - return CreateStrategy>(context, options, behavior); - }, - options); - } - - [UnconditionalSuppressMessage( - "Trimming", - "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", - Justification = "All options members preserved.")] - private static TBuilder AddSimpleCircuitBreakerCore(this TBuilder builder, SimpleCircuitBreakerStrategyOptions options) - where TBuilder : ResilienceStrategyBuilderBase - { - return builder.AddStrategy( - context => - { - return CreateStrategy>( - context, - options, - new ConsecutiveFailuresCircuitBehavior(options.FailureThreshold)); + return CreateStrategy>(context, options, behavior); }, options); } diff --git a/src/Polly.Core/CircuitBreaker/CircuitBreakerStateProvider.cs b/src/Polly.Core/CircuitBreaker/CircuitBreakerStateProvider.cs index 1f763941f5..36782577ad 100644 --- a/src/Polly.Core/CircuitBreaker/CircuitBreakerStateProvider.cs +++ b/src/Polly.Core/CircuitBreaker/CircuitBreakerStateProvider.cs @@ -38,5 +38,5 @@ internal void Initialize(Func circuitStateProvider, Func /// This will be null if no exceptions or results have been handled by the circuit-breaker since the circuit last closed. /// - public Outcome? LastHandledOutcome => _lastHandledOutcomeProvider?.Invoke(); + internal Outcome? LastHandledOutcome => _lastHandledOutcomeProvider?.Invoke(); } diff --git a/src/Polly.Core/CircuitBreaker/CircuitBreakerStrategyOptions.TResult.cs b/src/Polly.Core/CircuitBreaker/CircuitBreakerStrategyOptions.TResult.cs new file mode 100644 index 0000000000..15e1801a80 --- /dev/null +++ b/src/Polly.Core/CircuitBreaker/CircuitBreakerStrategyOptions.TResult.cs @@ -0,0 +1,137 @@ +using System.ComponentModel.DataAnnotations; + +namespace Polly.CircuitBreaker; + +/// +/// The options for circuit breaker resilience strategy. +/// +/// The type of result the circuit breaker strategy handles. +/// +/// The circuit will break if, within any time-slice of duration , +/// the proportion of actions resulting in a handled exception exceeds , +/// provided also that the number of actions through the circuit in the time-slice is at least . +/// +/// The circuit will stay broken for the . +/// Any attempt to execute this while the circuit is broken, will immediately throw a containing the exception +/// that broke the circuit. +/// +/// +/// If the first action after the break duration period results in a handled exception, the circuit will break +/// again for another ; if no exception is thrown, the circuit will reset. +/// +/// +public class CircuitBreakerStrategyOptions : ResilienceStrategyOptions +{ + /// + /// Gets or sets the failure threshold at which the circuit will break. + /// + /// + /// A number between zero and one (inclusive) e.g. 0.5 represents breaking if 50% or more of actions result in a handled failure. + /// + /// A ratio number higher than 0, up to 1. The default value is 0.1 (i.e. 10%). + [Range(0, 1.0)] + public double FailureRatio { get; set; } = CircuitBreakerConstants.DefaultFailureRatio; + + /// + /// Gets or sets the minimum throughput: this many actions or more must pass through the circuit in the time-slice, + /// for statistics to be considered significant and the circuit-breaker to come into action. + /// + /// + /// The default value is 0.1 (i.e. 10%). The value must be 2 or greater. + /// + [Range(CircuitBreakerConstants.MinimumValidThroughput, int.MaxValue)] + public int MinimumThroughput { get; set; } = CircuitBreakerConstants.DefaultMinimumThroughput; + +#pragma warning disable IL2026 // Addressed with DynamicDependency on ValidationHelper.Validate method + /// + /// Gets or sets the duration of the sampling over which failure ratios are assessed. + /// + /// + /// The default value is 30 seconds. Value must be greater than 0.5 seconds. + /// + [Range(typeof(TimeSpan), "00:00:00.500", "1.00:00:00")] + public TimeSpan SamplingDuration { get; set; } = CircuitBreakerConstants.DefaultSamplingDuration; +#pragma warning restore IL2026 + +#pragma warning disable IL2026 // Addressed with DynamicDependency on ValidationHelper.Validate method + /// + /// Gets or sets the duration of break the circuit will stay open before resetting. + /// + /// + /// The default value is 5 seconds. Value must be greater than 0.5 seconds. + /// + [Range(typeof(TimeSpan), "00:00:00.500", "1.00:00:00")] + public TimeSpan BreakDuration { get; set; } = CircuitBreakerConstants.DefaultBreakDuration; +#pragma warning restore + + /// + /// Gets or sets the predicates for the circuit breaker. + /// + /// + /// The default value is a predicate that handles circuit breaker on any exception except . + /// This property is required. + /// + [Required] + public Func, ValueTask> ShouldHandle { get; set; } = DefaultPredicates.HandleOutcome; + + /// + /// Gets or sets the event that is raised when the circuit resets to a state. + /// + /// + /// The callbacks registered to this event are invoked with eventual consistency. There is no guarantee that the circuit breaker + /// doesn't change the state before the callbacks finish. If you need to know the up-to-date state of the circuit breaker use + /// the property. + /// + /// Note that these events might be executed asynchronously at a later time when the circuit state is no longer the same as at the point of invocation of the event. + /// However, the invocation order of the , , and events is always + /// maintained to ensure the correct sequence of state transitions. + /// + /// + /// The default value is . + public Func, ValueTask>? OnClosed { get; set; } + + /// + /// Gets or sets the event that is raised when the circuit transitions to an state. + /// + /// + /// The callbacks registered to this event are invoked with eventual consistency. There is no guarantee that the circuit breaker + /// doesn't change the state before the callbacks finish. If you need to know the up-to-date state of the circuit breaker use + /// the property. + /// + /// Note that these events might be executed asynchronously at a later time when the circuit state is no longer the same as at the point of invocation of the event. + /// However, the invocation order of the , , and events is always + /// maintained to ensure the correct sequence of state transitions. + /// + /// + /// The default value is . + public Func, ValueTask>? OnOpened { get; set; } + + /// + /// Gets or sets the event that is raised when when the circuit transitions to an state. + /// + /// + /// The callbacks registered to this event are invoked with eventual consistency. There is no guarantee that the circuit breaker + /// doesn't change the state before the callbacks finish. If you need to know the up-to-date state of the circuit breaker use + /// the property. + /// + /// Note that these events might be executed asynchronously at a later time when the circuit state is no longer the same as at the point of invocation of the event. + /// However, the invocation order of the , , and events is always + /// maintained to ensure the correct sequence of state transitions. + /// + /// + /// The default value is . + public Func? OnHalfOpened { get; set; } + + /// + /// Gets or sets the manual control for the circuit breaker. + /// + /// The default value is . + public CircuitBreakerManualControl? ManualControl { get; set; } + + /// + /// Gets or sets the state provider for the circuit breaker. + /// + /// The default value is . + public CircuitBreakerStateProvider? StateProvider { get; set; } +} + diff --git a/src/Polly.Core/CircuitBreaker/CircuitBreakerStrategyOptions.cs b/src/Polly.Core/CircuitBreaker/CircuitBreakerStrategyOptions.cs index c55cc6aa59..c4bdce525b 100644 --- a/src/Polly.Core/CircuitBreaker/CircuitBreakerStrategyOptions.cs +++ b/src/Polly.Core/CircuitBreaker/CircuitBreakerStrategyOptions.cs @@ -1,101 +1,6 @@ -using System.ComponentModel.DataAnnotations; - namespace Polly.CircuitBreaker; -/// -/// The base options for circuit breaker resilience strategy. -/// -/// The type of result the circuit breaker strategy handles. -/// -/// The circuit will stay broken for the . Any attempt to execute the resilience strategy -/// while the circuit is broken, will immediately throw a containing the exception or result -/// that broke the circuit. -/// -/// If the first action after the break duration period results in a handled exception or result, the circuit will break -/// again for another ; if no exception or handled result is encountered, the circuit will reset. -/// -/// -public abstract class CircuitBreakerStrategyOptions : ResilienceStrategyOptions +/// +public class CircuitBreakerStrategyOptions : CircuitBreakerStrategyOptions { -#pragma warning disable IL2026 // Addressed with DynamicDependency on ValidationHelper.Validate method - /// - /// Gets or sets the duration of break the circuit will stay open before resetting. - /// - /// - /// The default value is 5 seconds. Value must be greater than 0.5 seconds. - /// - [Range(typeof(TimeSpan), "00:00:00.500", "1.00:00:00")] - public TimeSpan BreakDuration { get; set; } = CircuitBreakerConstants.DefaultBreakDuration; -#pragma warning restore - - /// - /// Gets or sets the predicates for the circuit breaker. - /// - /// - /// The default value is a predicate that handles circuit breaker on any exception except . - /// This property is required. - /// - [Required] - public Func, ValueTask> ShouldHandle { get; set; } = DefaultPredicates.HandleOutcome; - - /// - /// Gets or sets the event that is raised when the circuit resets to a state. - /// - /// - /// The callbacks registered to this event are invoked with eventual consistency. There is no guarantee that the circuit breaker - /// doesn't change the state before the callbacks finish. If you need to know the up-to-date state of the circuit breaker use - /// the property. - /// - /// Note that these events might be executed asynchronously at a later time when the circuit state is no longer the same as at the point of invocation of the event. - /// However, the invocation order of the , , and events is always - /// maintained to ensure the correct sequence of state transitions. - /// - /// - /// The default value is . - public Func, ValueTask>? OnClosed { get; set; } - - /// - /// Gets or sets the event that is raised when the circuit transitions to an state. - /// - /// - /// The callbacks registered to this event are invoked with eventual consistency. There is no guarantee that the circuit breaker - /// doesn't change the state before the callbacks finish. If you need to know the up-to-date state of the circuit breaker use - /// the property. - /// - /// Note that these events might be executed asynchronously at a later time when the circuit state is no longer the same as at the point of invocation of the event. - /// However, the invocation order of the , , and events is always - /// maintained to ensure the correct sequence of state transitions. - /// - /// - /// The default value is . - public Func, ValueTask>? OnOpened { get; set; } - - /// - /// Gets or sets the event that is raised when when the circuit transitions to an state. - /// - /// - /// The callbacks registered to this event are invoked with eventual consistency. There is no guarantee that the circuit breaker - /// doesn't change the state before the callbacks finish. If you need to know the up-to-date state of the circuit breaker use - /// the property. - /// - /// Note that these events might be executed asynchronously at a later time when the circuit state is no longer the same as at the point of invocation of the event. - /// However, the invocation order of the , , and events is always - /// maintained to ensure the correct sequence of state transitions. - /// - /// - /// The default value is . - public Func? OnHalfOpened { get; set; } - - /// - /// Gets or sets the manual control for the circuit breaker. - /// - /// The default value is . - public CircuitBreakerManualControl? ManualControl { get; set; } - - /// - /// Gets or sets the state provider for the circuit breaker. - /// - /// The default value is . - public CircuitBreakerStateProvider? StateProvider { get; set; } } - diff --git a/src/Polly.Core/CircuitBreaker/Controller/AdvancedCircuitBehavior.cs b/src/Polly.Core/CircuitBreaker/Controller/AdvancedCircuitBehavior.cs index e373e27676..8cfc1cb472 100644 --- a/src/Polly.Core/CircuitBreaker/Controller/AdvancedCircuitBehavior.cs +++ b/src/Polly.Core/CircuitBreaker/Controller/AdvancedCircuitBehavior.cs @@ -5,13 +5,13 @@ namespace Polly.CircuitBreaker; internal sealed class AdvancedCircuitBehavior : CircuitBehavior { private readonly HealthMetrics _metrics; - private readonly double _failureThreshold; + private readonly double _failureRatio; private readonly int _minimumThroughput; - public AdvancedCircuitBehavior(double failureThreshold, int minimumThroughput, HealthMetrics metrics) + public AdvancedCircuitBehavior(double failureRatio, int minimumThroughput, HealthMetrics metrics) { _metrics = metrics; - _failureThreshold = failureThreshold; + _failureRatio = failureRatio; _minimumThroughput = minimumThroughput; } @@ -24,7 +24,7 @@ public override void OnActionFailure(CircuitState currentState, out bool shouldB case CircuitState.Closed: _metrics.IncrementFailure(); var info = _metrics.GetHealthInfo(); - shouldBreak = info.Throughput >= _minimumThroughput && info.FailureRate >= _failureThreshold; + shouldBreak = info.Throughput >= _minimumThroughput && info.FailureRate >= _failureRatio; break; case CircuitState.Open: diff --git a/src/Polly.Core/CircuitBreaker/Controller/ConsecutiveFailuresCircuitBehavior.cs b/src/Polly.Core/CircuitBreaker/Controller/ConsecutiveFailuresCircuitBehavior.cs deleted file mode 100644 index 8d8d13e896..0000000000 --- a/src/Polly.Core/CircuitBreaker/Controller/ConsecutiveFailuresCircuitBehavior.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace Polly.CircuitBreaker; - -internal sealed class ConsecutiveFailuresCircuitBehavior : CircuitBehavior -{ - private readonly int _failureThreshold; - private int _consecutiveFailures; - - public ConsecutiveFailuresCircuitBehavior(int failureThreshold) => _failureThreshold = failureThreshold; - - public override void OnActionSuccess(CircuitState currentState) - { - if (currentState == CircuitState.Closed) - { - _consecutiveFailures = 0; - } - } - - public override void OnActionFailure(CircuitState currentState, out bool shouldBreak) - { - shouldBreak = false; - - if (currentState == CircuitState.Closed) - { - _consecutiveFailures += 1; - if (_consecutiveFailures >= _failureThreshold) - { - shouldBreak = true; - } - } - } - - public override void OnCircuitClosed() - { - _consecutiveFailures = 0; - } -} - diff --git a/src/Polly.Core/CircuitBreaker/SimpleCircuitBreakerStrategyOptions.TResult.cs b/src/Polly.Core/CircuitBreaker/SimpleCircuitBreakerStrategyOptions.TResult.cs deleted file mode 100644 index 2c2c032012..0000000000 --- a/src/Polly.Core/CircuitBreaker/SimpleCircuitBreakerStrategyOptions.TResult.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace Polly.CircuitBreaker; - -/// -/// The options for the simple circuit breaker resilience strategy. -/// -/// The type of result the circuit breaker strategy handles. -/// -/// The circuit will break if exceptions or results that are handled by the resilience strategy are encountered consecutively. -/// -/// The circuit will stay broken for the . Any attempt to execute the resilience strategy -/// while the circuit is broken, will immediately throw a containing the exception or result -/// that broke the circuit. -/// -/// -/// If the first action after the break duration period results in a handled exception or result, the circuit will break -/// again for another ; if no exception or handled result is encountered, the circuit will reset. -/// -/// -public class SimpleCircuitBreakerStrategyOptions : CircuitBreakerStrategyOptions -{ - /// - /// Gets or sets the number of the outcome failures handled by before opening the circuit. - /// - /// - /// The default value is 100. Must be greater than 0. - /// - [Range(1, int.MaxValue)] - public int FailureThreshold { get; set; } = CircuitBreakerConstants.DefaultFailureThreshold; -} diff --git a/src/Polly.Core/CircuitBreaker/SimpleCircuitBreakerStrategyOptions.cs b/src/Polly.Core/CircuitBreaker/SimpleCircuitBreakerStrategyOptions.cs deleted file mode 100644 index f1e32fee11..0000000000 --- a/src/Polly.Core/CircuitBreaker/SimpleCircuitBreakerStrategyOptions.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Polly.CircuitBreaker; - -/// -public class SimpleCircuitBreakerStrategyOptions : SimpleCircuitBreakerStrategyOptions -{ -} diff --git a/src/Polly.Core/PublicAPI.Unshipped.txt b/src/Polly.Core/PublicAPI.Unshipped.txt index 3b79f68fc0..1ca2da242d 100644 --- a/src/Polly.Core/PublicAPI.Unshipped.txt +++ b/src/Polly.Core/PublicAPI.Unshipped.txt @@ -11,16 +11,6 @@ override Polly.ResiliencePropertyKey.Equals(object? obj) -> bool override Polly.ResiliencePropertyKey.GetHashCode() -> int override Polly.ResiliencePropertyKey.ToString() -> string! override Polly.Telemetry.ResilienceEvent.ToString() -> string! -Polly.CircuitBreaker.AdvancedCircuitBreakerStrategyOptions -Polly.CircuitBreaker.AdvancedCircuitBreakerStrategyOptions.AdvancedCircuitBreakerStrategyOptions() -> void -Polly.CircuitBreaker.AdvancedCircuitBreakerStrategyOptions -Polly.CircuitBreaker.AdvancedCircuitBreakerStrategyOptions.AdvancedCircuitBreakerStrategyOptions() -> void -Polly.CircuitBreaker.AdvancedCircuitBreakerStrategyOptions.FailureThreshold.get -> double -Polly.CircuitBreaker.AdvancedCircuitBreakerStrategyOptions.FailureThreshold.set -> void -Polly.CircuitBreaker.AdvancedCircuitBreakerStrategyOptions.MinimumThroughput.get -> int -Polly.CircuitBreaker.AdvancedCircuitBreakerStrategyOptions.MinimumThroughput.set -> void -Polly.CircuitBreaker.AdvancedCircuitBreakerStrategyOptions.SamplingDuration.get -> System.TimeSpan -Polly.CircuitBreaker.AdvancedCircuitBreakerStrategyOptions.SamplingDuration.set -> void Polly.CircuitBreaker.BrokenCircuitException Polly.CircuitBreaker.BrokenCircuitException.BrokenCircuitException() -> void Polly.CircuitBreaker.BrokenCircuitException.BrokenCircuitException(string! message) -> void @@ -41,19 +31,26 @@ Polly.CircuitBreaker.CircuitBreakerPredicateArguments.CircuitBreakerPredicateArg Polly.CircuitBreaker.CircuitBreakerStateProvider Polly.CircuitBreaker.CircuitBreakerStateProvider.CircuitBreakerStateProvider() -> void Polly.CircuitBreaker.CircuitBreakerStateProvider.CircuitState.get -> Polly.CircuitBreaker.CircuitState -Polly.CircuitBreaker.CircuitBreakerStateProvider.LastHandledOutcome.get -> Polly.Outcome? +Polly.CircuitBreaker.CircuitBreakerStrategyOptions +Polly.CircuitBreaker.CircuitBreakerStrategyOptions.CircuitBreakerStrategyOptions() -> void Polly.CircuitBreaker.CircuitBreakerStrategyOptions Polly.CircuitBreaker.CircuitBreakerStrategyOptions.BreakDuration.get -> System.TimeSpan Polly.CircuitBreaker.CircuitBreakerStrategyOptions.BreakDuration.set -> void Polly.CircuitBreaker.CircuitBreakerStrategyOptions.CircuitBreakerStrategyOptions() -> void +Polly.CircuitBreaker.CircuitBreakerStrategyOptions.FailureRatio.get -> double +Polly.CircuitBreaker.CircuitBreakerStrategyOptions.FailureRatio.set -> void Polly.CircuitBreaker.CircuitBreakerStrategyOptions.ManualControl.get -> Polly.CircuitBreaker.CircuitBreakerManualControl? Polly.CircuitBreaker.CircuitBreakerStrategyOptions.ManualControl.set -> void +Polly.CircuitBreaker.CircuitBreakerStrategyOptions.MinimumThroughput.get -> int +Polly.CircuitBreaker.CircuitBreakerStrategyOptions.MinimumThroughput.set -> void Polly.CircuitBreaker.CircuitBreakerStrategyOptions.OnClosed.get -> System.Func, System.Threading.Tasks.ValueTask>? Polly.CircuitBreaker.CircuitBreakerStrategyOptions.OnClosed.set -> void Polly.CircuitBreaker.CircuitBreakerStrategyOptions.OnHalfOpened.get -> System.Func? Polly.CircuitBreaker.CircuitBreakerStrategyOptions.OnHalfOpened.set -> void Polly.CircuitBreaker.CircuitBreakerStrategyOptions.OnOpened.get -> System.Func, System.Threading.Tasks.ValueTask>? Polly.CircuitBreaker.CircuitBreakerStrategyOptions.OnOpened.set -> void +Polly.CircuitBreaker.CircuitBreakerStrategyOptions.SamplingDuration.get -> System.TimeSpan +Polly.CircuitBreaker.CircuitBreakerStrategyOptions.SamplingDuration.set -> void Polly.CircuitBreaker.CircuitBreakerStrategyOptions.ShouldHandle.get -> System.Func, System.Threading.Tasks.ValueTask>! Polly.CircuitBreaker.CircuitBreakerStrategyOptions.ShouldHandle.set -> void Polly.CircuitBreaker.CircuitBreakerStrategyOptions.StateProvider.get -> Polly.CircuitBreaker.CircuitBreakerStateProvider? @@ -77,12 +74,6 @@ Polly.CircuitBreaker.OnCircuitOpenedArguments Polly.CircuitBreaker.OnCircuitOpenedArguments.BreakDuration.get -> System.TimeSpan Polly.CircuitBreaker.OnCircuitOpenedArguments.IsManual.get -> bool Polly.CircuitBreaker.OnCircuitOpenedArguments.OnCircuitOpenedArguments(System.TimeSpan breakDuration, bool isManual) -> void -Polly.CircuitBreaker.SimpleCircuitBreakerStrategyOptions -Polly.CircuitBreaker.SimpleCircuitBreakerStrategyOptions.SimpleCircuitBreakerStrategyOptions() -> void -Polly.CircuitBreaker.SimpleCircuitBreakerStrategyOptions -Polly.CircuitBreaker.SimpleCircuitBreakerStrategyOptions.FailureThreshold.get -> int -Polly.CircuitBreaker.SimpleCircuitBreakerStrategyOptions.FailureThreshold.set -> void -Polly.CircuitBreaker.SimpleCircuitBreakerStrategyOptions.SimpleCircuitBreakerStrategyOptions() -> void Polly.CircuitBreakerResilienceStrategyBuilderExtensions Polly.ExecutionRejectedException Polly.ExecutionRejectedException.ExecutionRejectedException() -> void @@ -391,10 +382,8 @@ Polly.Timeout.TimeoutStrategyOptions.TimeoutGenerator.set -> void Polly.Timeout.TimeoutStrategyOptions.TimeoutStrategyOptions() -> void Polly.TimeoutResilienceStrategyBuilderExtensions Polly.Utils.LegacySupport -static Polly.CircuitBreakerResilienceStrategyBuilderExtensions.AddAdvancedCircuitBreaker(this Polly.ResilienceStrategyBuilder! builder, Polly.CircuitBreaker.AdvancedCircuitBreakerStrategyOptions! options) -> Polly.ResilienceStrategyBuilder! -static Polly.CircuitBreakerResilienceStrategyBuilderExtensions.AddAdvancedCircuitBreaker(this Polly.ResilienceStrategyBuilder! builder, Polly.CircuitBreaker.AdvancedCircuitBreakerStrategyOptions! options) -> Polly.ResilienceStrategyBuilder! -static Polly.CircuitBreakerResilienceStrategyBuilderExtensions.AddSimpleCircuitBreaker(this Polly.ResilienceStrategyBuilder! builder, Polly.CircuitBreaker.SimpleCircuitBreakerStrategyOptions! options) -> Polly.ResilienceStrategyBuilder! -static Polly.CircuitBreakerResilienceStrategyBuilderExtensions.AddSimpleCircuitBreaker(this Polly.ResilienceStrategyBuilder! builder, Polly.CircuitBreaker.SimpleCircuitBreakerStrategyOptions! options) -> Polly.ResilienceStrategyBuilder! +static Polly.CircuitBreakerResilienceStrategyBuilderExtensions.AddCircuitBreaker(this Polly.ResilienceStrategyBuilder! builder, Polly.CircuitBreaker.CircuitBreakerStrategyOptions! options) -> Polly.ResilienceStrategyBuilder! +static Polly.CircuitBreakerResilienceStrategyBuilderExtensions.AddCircuitBreaker(this Polly.ResilienceStrategyBuilder! builder, Polly.CircuitBreaker.CircuitBreakerStrategyOptions! options) -> Polly.ResilienceStrategyBuilder! static Polly.FallbackResilienceStrategyBuilderExtensions.AddFallback(this Polly.ResilienceStrategyBuilder! builder, Polly.Fallback.FallbackStrategyOptions! options) -> Polly.ResilienceStrategyBuilder! static Polly.HedgingResilienceStrategyBuilderExtensions.AddHedging(this Polly.ResilienceStrategyBuilder! builder, Polly.Hedging.HedgingStrategyOptions! options) -> Polly.ResilienceStrategyBuilder! static Polly.Outcome.FromException(System.Exception! exception) -> Polly.Outcome diff --git a/test/Polly.Core.Tests/CircuitBreaker/AdvancedCircuitBreakerOptionsTests.cs b/test/Polly.Core.Tests/CircuitBreaker/CircuitBreakerOptionsTests.cs similarity index 85% rename from test/Polly.Core.Tests/CircuitBreaker/AdvancedCircuitBreakerOptionsTests.cs rename to test/Polly.Core.Tests/CircuitBreaker/CircuitBreakerOptionsTests.cs index 73babb1327..6473dbacf9 100644 --- a/test/Polly.Core.Tests/CircuitBreaker/AdvancedCircuitBreakerOptionsTests.cs +++ b/test/Polly.Core.Tests/CircuitBreaker/CircuitBreakerOptionsTests.cs @@ -4,14 +4,14 @@ namespace Polly.Core.Tests.CircuitBreaker; -public class AdvancedCircuitBreakerOptionsTests +public class CircuitBreakerOptionsTests { [Fact] public void Ctor_Defaults() { - var options = new AdvancedCircuitBreakerStrategyOptions(); + var options = new CircuitBreakerStrategyOptions(); options.BreakDuration.Should().Be(TimeSpan.FromSeconds(5)); - options.FailureThreshold.Should().Be(0.1); + options.FailureRatio.Should().Be(0.1); options.MinimumThroughput.Should().Be(100); options.SamplingDuration.Should().Be(TimeSpan.FromSeconds(30)); options.OnOpened.Should().BeNull(); @@ -21,7 +21,7 @@ public void Ctor_Defaults() options.Name.Should().BeNull(); // now set to min values - options.FailureThreshold = 0.001; + options.FailureRatio = 0.001; options.BreakDuration = TimeSpan.FromMilliseconds(500); options.MinimumThroughput = 2; options.SamplingDuration = TimeSpan.FromMilliseconds(500); @@ -32,7 +32,7 @@ public void Ctor_Defaults() [Fact] public async Task ShouldHandle_EnsureDefaults() { - var options = new AdvancedCircuitBreakerStrategyOptions(); + var options = new CircuitBreakerStrategyOptions(); var args = default(CircuitBreakerPredicateArguments); var context = ResilienceContextPool.Shared.Get(); @@ -44,10 +44,10 @@ public async Task ShouldHandle_EnsureDefaults() [Fact] public void Ctor_Generic_Defaults() { - var options = new AdvancedCircuitBreakerStrategyOptions(); + var options = new CircuitBreakerStrategyOptions(); options.BreakDuration.Should().Be(TimeSpan.FromSeconds(5)); - options.FailureThreshold.Should().Be(0.1); + options.FailureRatio.Should().Be(0.1); options.MinimumThroughput.Should().Be(100); options.SamplingDuration.Should().Be(TimeSpan.FromSeconds(30)); options.OnOpened.Should().BeNull(); @@ -57,7 +57,7 @@ public void Ctor_Generic_Defaults() options.Name.Should().BeNull(); // now set to min values - options.FailureThreshold = 0.001; + options.FailureRatio = 0.001; options.BreakDuration = TimeSpan.FromMilliseconds(500); options.MinimumThroughput = 2; options.SamplingDuration = TimeSpan.FromMilliseconds(500); @@ -68,10 +68,10 @@ public void Ctor_Generic_Defaults() [Fact] public void InvalidOptions_Validate() { - var options = new AdvancedCircuitBreakerStrategyOptions + var options = new CircuitBreakerStrategyOptions { BreakDuration = TimeSpan.FromMilliseconds(299), - FailureThreshold = 0, + FailureRatio = 0, SamplingDuration = TimeSpan.Zero, MinimumThroughput = 0, OnOpened = null!, diff --git a/test/Polly.Core.Tests/CircuitBreaker/CircuitBreakerResilienceStrategyBuilderTests.cs b/test/Polly.Core.Tests/CircuitBreaker/CircuitBreakerResilienceStrategyBuilderTests.cs index c184624849..0e0cac1de8 100644 --- a/test/Polly.Core.Tests/CircuitBreaker/CircuitBreakerResilienceStrategyBuilderTests.cs +++ b/test/Polly.Core.Tests/CircuitBreaker/CircuitBreakerResilienceStrategyBuilderTests.cs @@ -8,11 +8,7 @@ public class CircuitBreakerResilienceStrategyBuilderTests { public static TheoryData> ConfigureData = new() { - builder => builder.AddAdvancedCircuitBreaker(new AdvancedCircuitBreakerStrategyOptions - { - ShouldHandle = _ => PredicateResult.True - }), - builder => builder.AddSimpleCircuitBreaker(new SimpleCircuitBreakerStrategyOptions + builder => builder.AddCircuitBreaker(new CircuitBreakerStrategyOptions { ShouldHandle = _ => PredicateResult.True }), @@ -20,11 +16,7 @@ public class CircuitBreakerResilienceStrategyBuilderTests public static TheoryData>> ConfigureDataGeneric = new() { - builder => builder.AddAdvancedCircuitBreaker(new AdvancedCircuitBreakerStrategyOptions - { - ShouldHandle = _ => PredicateResult.True - }), - builder => builder.AddSimpleCircuitBreaker(new SimpleCircuitBreakerStrategyOptions + builder => builder.AddCircuitBreaker(new CircuitBreakerStrategyOptions { ShouldHandle = _ => PredicateResult.True }), @@ -60,26 +52,12 @@ public void AddCircuitBreaker_Generic_Configure(Action() - .Invoking(b => b.AddSimpleCircuitBreaker(new SimpleCircuitBreakerStrategyOptions { BreakDuration = TimeSpan.MinValue })) + .Invoking(b => b.AddCircuitBreaker(new CircuitBreakerStrategyOptions { BreakDuration = TimeSpan.MinValue })) .Should() .Throw(); new ResilienceStrategyBuilder() - .Invoking(b => b.AddSimpleCircuitBreaker(new SimpleCircuitBreakerStrategyOptions { BreakDuration = TimeSpan.MinValue })) - .Should() - .Throw(); - } - - [Fact] - public void AddAdvancedCircuitBreaker_Validation() - { - new ResilienceStrategyBuilder() - .Invoking(b => b.AddAdvancedCircuitBreaker(new AdvancedCircuitBreakerStrategyOptions { BreakDuration = TimeSpan.MinValue })) - .Should() - .Throw(); - - new ResilienceStrategyBuilder() - .Invoking(b => b.AddAdvancedCircuitBreaker(new AdvancedCircuitBreakerStrategyOptions { BreakDuration = TimeSpan.MinValue })) + .Invoking(b => b.AddCircuitBreaker(new CircuitBreakerStrategyOptions { BreakDuration = TimeSpan.MinValue })) .Should() .Throw(); } @@ -91,56 +69,9 @@ public void AddCircuitBreaker_IntegrationTest() int closed = 0; int halfOpened = 0; - var options = new SimpleCircuitBreakerStrategyOptions - { - FailureThreshold = 5, - BreakDuration = TimeSpan.FromMilliseconds(500), - ShouldHandle = args => new ValueTask(args.Result is -1), - OnOpened = _ => { opened++; return default; }, - OnClosed = _ => { closed++; return default; }, - OnHalfOpened = (_) => { halfOpened++; return default; } - }; - - var timeProvider = new FakeTimeProvider(); - var strategy = new ResilienceStrategyBuilder { TimeProvider = timeProvider }.AddSimpleCircuitBreaker(options).Build(); - - for (int i = 0; i < options.FailureThreshold; i++) - { - strategy.Execute(_ => -1); - } - - // Circuit opened - opened.Should().Be(1); - halfOpened.Should().Be(0); - closed.Should().Be(0); - Assert.Throws>(() => strategy.Execute(_ => 0)); - - // Circuit Half Opened - timeProvider.Advance(options.BreakDuration); - strategy.Execute(_ => -1); - Assert.Throws>(() => strategy.Execute(_ => 0)); - opened.Should().Be(2); - halfOpened.Should().Be(1); - closed.Should().Be(0); - - // Now close it - timeProvider.Advance(options.BreakDuration); - strategy.Execute(_ => 0); - opened.Should().Be(2); - halfOpened.Should().Be(2); - closed.Should().Be(1); - } - - [Fact] - public void AddAdvancedCircuitBreaker_IntegrationTest() - { - int opened = 0; - int closed = 0; - int halfOpened = 0; - - var options = new AdvancedCircuitBreakerStrategyOptions + var options = new CircuitBreakerStrategyOptions { - FailureThreshold = 0.5, + FailureRatio = 0.5, MinimumThroughput = 10, SamplingDuration = TimeSpan.FromSeconds(10), BreakDuration = TimeSpan.FromSeconds(1), @@ -151,7 +82,7 @@ public void AddAdvancedCircuitBreaker_IntegrationTest() }; var timeProvider = new FakeTimeProvider(); - var strategy = new ResilienceStrategyBuilder { TimeProvider = timeProvider }.AddAdvancedCircuitBreaker(options).Build(); + var strategy = new ResilienceStrategyBuilder { TimeProvider = timeProvider }.AddCircuitBreaker(options).Build(); for (int i = 0; i < 10; i++) { @@ -187,11 +118,11 @@ public async Task AddCircuitBreakers_WithIsolatedManualControl_ShouldBeIsolated( await manualControl.IsolateAsync(); var strategy1 = new ResilienceStrategyBuilder() - .AddAdvancedCircuitBreaker(new() { ManualControl = manualControl }) + .AddCircuitBreaker(new() { ManualControl = manualControl }) .Build(); var strategy2 = new ResilienceStrategyBuilder() - .AddAdvancedCircuitBreaker(new() { ManualControl = manualControl }) + .AddCircuitBreaker(new() { ManualControl = manualControl }) .Build(); strategy1.Invoking(s => s.Execute(() => { })).Should().Throw(); diff --git a/test/Polly.Core.Tests/CircuitBreaker/CircuitBreakerResilienceStrategyTests.cs b/test/Polly.Core.Tests/CircuitBreaker/CircuitBreakerResilienceStrategyTests.cs index 1bb236afe4..f81b2f4dfb 100644 --- a/test/Polly.Core.Tests/CircuitBreaker/CircuitBreakerResilienceStrategyTests.cs +++ b/test/Polly.Core.Tests/CircuitBreaker/CircuitBreakerResilienceStrategyTests.cs @@ -10,7 +10,7 @@ public class CircuitBreakerResilienceStrategyTests : IDisposable private readonly FakeTimeProvider _timeProvider; private readonly Mock _behavior; private readonly ResilienceStrategyTelemetry _telemetry; - private readonly SimpleCircuitBreakerStrategyOptions _options; + private readonly CircuitBreakerStrategyOptions _options; private readonly CircuitStateController _controller; public CircuitBreakerResilienceStrategyTests() @@ -18,7 +18,7 @@ public CircuitBreakerResilienceStrategyTests() _timeProvider = new FakeTimeProvider(); _behavior = new Mock(MockBehavior.Strict); _telemetry = TestUtilities.CreateResilienceTelemetry(Mock.Of()); - _options = new SimpleCircuitBreakerStrategyOptions(); + _options = new CircuitBreakerStrategyOptions(); _controller = new CircuitStateController( CircuitBreakerConstants.DefaultBreakDuration, null, diff --git a/test/Polly.Core.Tests/CircuitBreaker/Controller/AdvancedCircuitBehaviorTests.cs b/test/Polly.Core.Tests/CircuitBreaker/Controller/AdvancedCircuitBehaviorTests.cs index be8d8b58bc..ff768ca79d 100644 --- a/test/Polly.Core.Tests/CircuitBreaker/Controller/AdvancedCircuitBehaviorTests.cs +++ b/test/Polly.Core.Tests/CircuitBreaker/Controller/AdvancedCircuitBehaviorTests.cs @@ -69,6 +69,6 @@ public void OnCircuitClosed_Ok() private AdvancedCircuitBehavior Create() { - return new AdvancedCircuitBehavior(CircuitBreakerConstants.DefaultAdvancedFailureThreshold, CircuitBreakerConstants.DefaultMinimumThroughput, _metrics.Object); + return new AdvancedCircuitBehavior(CircuitBreakerConstants.DefaultFailureRatio, CircuitBreakerConstants.DefaultMinimumThroughput, _metrics.Object); } } diff --git a/test/Polly.Core.Tests/CircuitBreaker/Controller/CircuitStateControllerTests.cs b/test/Polly.Core.Tests/CircuitBreaker/Controller/CircuitStateControllerTests.cs index d937b33ac7..04115ef422 100644 --- a/test/Polly.Core.Tests/CircuitBreaker/Controller/CircuitStateControllerTests.cs +++ b/test/Polly.Core.Tests/CircuitBreaker/Controller/CircuitStateControllerTests.cs @@ -9,7 +9,7 @@ public class CircuitStateControllerTests { private readonly FakeTimeProvider _timeProvider = new(); - private readonly CircuitBreakerStrategyOptions _options = new SimpleCircuitBreakerStrategyOptions(); + private readonly CircuitBreakerStrategyOptions _options = new(); private readonly Mock _circuitBehavior = new(MockBehavior.Strict); private readonly Action _onTelemetry = _ => { }; diff --git a/test/Polly.Core.Tests/CircuitBreaker/Controller/ConsecutiveFailuresCircuitBehaviorTests.cs b/test/Polly.Core.Tests/CircuitBreaker/Controller/ConsecutiveFailuresCircuitBehaviorTests.cs deleted file mode 100644 index 7ee796e3ab..0000000000 --- a/test/Polly.Core.Tests/CircuitBreaker/Controller/ConsecutiveFailuresCircuitBehaviorTests.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Polly.CircuitBreaker; - -namespace Polly.Core.Tests.CircuitBreaker.Controller; -public class ConsecutiveFailuresCircuitBehaviorTests -{ - [Fact] - public void OnCircuitReset_Ok() - { - var behavior = new ConsecutiveFailuresCircuitBehavior(2); - - behavior.OnActionFailure(CircuitState.Closed, out var shouldBreak); - behavior.OnCircuitClosed(); - behavior.OnActionFailure(CircuitState.Closed, out shouldBreak); - - shouldBreak.Should().BeFalse(); - } - - [InlineData(1, 1, true)] - [InlineData(2, 1, false)] - [Theory] - public void OnActionFailure_Ok(int threshold, int failures, bool expectedShouldBreak) - { - var behavior = new ConsecutiveFailuresCircuitBehavior(threshold); - - for (int i = 0; i < failures - 1; i++) - { - behavior.OnActionFailure(CircuitState.Closed, out _); - } - - behavior.OnActionFailure(CircuitState.Closed, out var shouldBreak); - shouldBreak.Should().Be(expectedShouldBreak); - } - - [InlineData(CircuitState.Closed, false)] - [InlineData(CircuitState.Open, true)] - [InlineData(CircuitState.Isolated, true)] - [InlineData(CircuitState.HalfOpen, true)] - [Theory] - public void OnActionSuccess_Ok(CircuitState state, bool expected) - { - var behavior = new ConsecutiveFailuresCircuitBehavior(2); - - behavior.OnActionFailure(CircuitState.Closed, out var shouldBreak); - behavior.OnActionSuccess(state); - behavior.OnActionFailure(CircuitState.Closed, out shouldBreak); - - shouldBreak.Should().Be(expected); - } -} diff --git a/test/Polly.Core.Tests/CircuitBreaker/SimpleCircuitBreakerOptionsTests.cs b/test/Polly.Core.Tests/CircuitBreaker/SimpleCircuitBreakerOptionsTests.cs deleted file mode 100644 index 303a19503a..0000000000 --- a/test/Polly.Core.Tests/CircuitBreaker/SimpleCircuitBreakerOptionsTests.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using Polly.CircuitBreaker; -using Polly.Utils; - -namespace Polly.Core.Tests.CircuitBreaker; - -public class SimpleCircuitBreakerOptionsTests -{ - [Fact] - public void Ctor_Defaults() - { - var options = new SimpleCircuitBreakerStrategyOptions(); - - options.BreakDuration.Should().Be(TimeSpan.FromSeconds(5)); - options.FailureThreshold.Should().Be(100); - options.OnOpened.Should().BeNull(); - options.OnClosed.Should().BeNull(); - options.OnHalfOpened.Should().BeNull(); - options.ShouldHandle.Should().NotBeNull(); - options.Name.Should().BeNull(); - - // now set to min values - options.FailureThreshold = 1; - options.BreakDuration = TimeSpan.FromMilliseconds(500); - - ValidationHelper.ValidateObject(new(options, "Dummy.")); - } - - [Fact] - public async Task ShouldHandle_EnsureDefaults() - { - var options = new SimpleCircuitBreakerStrategyOptions(); - var args = default(CircuitBreakerPredicateArguments); - var context = ResilienceContextPool.Shared.Get(); - - (await options.ShouldHandle(new(context, Outcome.FromResult(""), args))).Should().Be(false); - (await options.ShouldHandle(new(context, Outcome.FromException(new OperationCanceledException()), args))).Should().Be(false); - (await options.ShouldHandle(new(context, Outcome.FromException(new InvalidOperationException()), args))).Should().Be(true); - } - - [Fact] - public void Ctor_Generic_Defaults() - { - var options = new SimpleCircuitBreakerStrategyOptions(); - - options.BreakDuration.Should().Be(TimeSpan.FromSeconds(5)); - options.FailureThreshold.Should().Be(100); - options.OnOpened.Should().BeNull(); - options.OnClosed.Should().BeNull(); - options.OnHalfOpened.Should().BeNull(); - options.ShouldHandle.Should().NotBeNull(); - options.Name.Should().BeNull(); - - // now set to min values - options.FailureThreshold = 1; - options.BreakDuration = TimeSpan.FromMilliseconds(500); - - options.ShouldHandle = _ => PredicateResult.True; - ValidationHelper.ValidateObject(new(options, "Dummy.")); - } - - [Fact] - public void InvalidOptions_Validate() - { - var options = new SimpleCircuitBreakerStrategyOptions - { - BreakDuration = TimeSpan.FromMilliseconds(299), - FailureThreshold = 0, - OnOpened = null!, - OnClosed = null!, - OnHalfOpened = null!, - ShouldHandle = null!, - }; - - options - .Invoking(o => ValidationHelper.ValidateObject(new(o, "Dummy."))) - .Should() - .Throw() - .WithMessage(""" - Dummy. - - Validation Errors: - The field FailureThreshold must be between 1 and 2147483647. - The field BreakDuration must be between 00:00:00.5000000 and 1.00:00:00. - The ShouldHandle field is required. - """); - } -} diff --git a/test/Polly.Core.Tests/Issues/IssuesTests.CircuitBreakerStateSharing_959.cs b/test/Polly.Core.Tests/Issues/IssuesTests.CircuitBreakerStateSharing_959.cs index 712667c241..c2425ebdb5 100644 --- a/test/Polly.Core.Tests/Issues/IssuesTests.CircuitBreakerStateSharing_959.cs +++ b/test/Polly.Core.Tests/Issues/IssuesTests.CircuitBreakerStateSharing_959.cs @@ -7,9 +7,9 @@ public partial class IssuesTests [Fact] public void CircuitBreakerStateSharing_959() { - var options = new AdvancedCircuitBreakerStrategyOptions + var options = new CircuitBreakerStrategyOptions { - FailureThreshold = 1, + FailureRatio = 1, MinimumThroughput = 10, ShouldHandle = args => args.Result switch { @@ -23,7 +23,7 @@ public void CircuitBreakerStateSharing_959() }; // create the strategy - var strategy = new ResilienceStrategyBuilder { TimeProvider = TimeProvider }.AddAdvancedCircuitBreaker(options).Build(); + var strategy = new ResilienceStrategyBuilder { TimeProvider = TimeProvider }.AddCircuitBreaker(options).Build(); // now trigger the circuit breaker by evaluating multiple result types for (int i = 0; i < 5; i++) diff --git a/test/Polly.Core.Tests/PredicateBuilderTests.cs b/test/Polly.Core.Tests/PredicateBuilderTests.cs index 68e3038943..894f15efc7 100644 --- a/test/Polly.Core.Tests/PredicateBuilderTests.cs +++ b/test/Polly.Core.Tests/PredicateBuilderTests.cs @@ -100,7 +100,7 @@ public async Task Operator_HedgingStrategyOptions_Ok() [Fact] public async Task Operator_AdvancedCircuitBreakerStrategyOptions_Ok() { - var options = new AdvancedCircuitBreakerStrategyOptions + var options = new CircuitBreakerStrategyOptions { ShouldHandle = new PredicateBuilder().HandleResult("error") }; diff --git a/test/Polly.Extensions.Tests/Issues/IssuesTests.OnCircuitBreakWithServiceProvider_796.cs b/test/Polly.Extensions.Tests/Issues/IssuesTests.OnCircuitBreakWithServiceProvider_796.cs index 57cc47d92a..593f8308dc 100644 --- a/test/Polly.Extensions.Tests/Issues/IssuesTests.OnCircuitBreakWithServiceProvider_796.cs +++ b/test/Polly.Extensions.Tests/Issues/IssuesTests.OnCircuitBreakWithServiceProvider_796.cs @@ -17,9 +17,9 @@ public async Task OnCircuitBreakWithServiceProvider_796() { builder .AddStrategy(new ServiceProviderStrategy(context.ServiceProvider)) - .AddAdvancedCircuitBreaker(new AdvancedCircuitBreakerStrategyOptions + .AddCircuitBreaker(new CircuitBreakerStrategyOptions { - FailureThreshold = 1, + FailureRatio = 1, MinimumThroughput = 10, OnOpened = async args => { diff --git a/test/Polly.Extensions.Tests/Issues/IssuesTests.StrategiesPerEndpoint_1365.cs b/test/Polly.Extensions.Tests/Issues/IssuesTests.StrategiesPerEndpoint_1365.cs index 3f6e4aa65c..429f756406 100644 --- a/test/Polly.Extensions.Tests/Issues/IssuesTests.StrategiesPerEndpoint_1365.cs +++ b/test/Polly.Extensions.Tests/Issues/IssuesTests.StrategiesPerEndpoint_1365.cs @@ -56,7 +56,7 @@ public void StrategiesPerEndpoint_1365() } // apply circuit breaker - builder.AddAdvancedCircuitBreaker(new() + builder.AddCircuitBreaker(new() { BreakDuration = endpointOptions.BreakDuration, Name = $"{context.StrategyKey.EndpointName}-{context.StrategyKey.Resource}-CircuitBreaker" diff --git a/test/Polly.Testing.Tests/ResilienceStrategyExtensionsTests.cs b/test/Polly.Testing.Tests/ResilienceStrategyExtensionsTests.cs index c2729e90f0..48a4a6692c 100644 --- a/test/Polly.Testing.Tests/ResilienceStrategyExtensionsTests.cs +++ b/test/Polly.Testing.Tests/ResilienceStrategyExtensionsTests.cs @@ -23,7 +23,7 @@ public void GetInnerStrategies_Ok() FallbackAction = _ => Outcome.FromResultAsTask("dummy"), }) .AddRetry(new()) - .AddAdvancedCircuitBreaker(new()) + .AddCircuitBreaker(new()) .AddTimeout(TimeSpan.FromSeconds(1)) .AddHedging(new()) .AddConcurrencyLimiter(10) @@ -40,7 +40,7 @@ public void GetInnerStrategies_Ok() descriptor.Strategies.Should().HaveCount(7); descriptor.Strategies[0].Options.Should().BeOfType>(); descriptor.Strategies[1].Options.Should().BeOfType>(); - descriptor.Strategies[2].Options.Should().BeOfType>(); + descriptor.Strategies[2].Options.Should().BeOfType>(); descriptor.Strategies[3].Options.Should().BeOfType(); descriptor.Strategies[3].Options .Should() From 08f27aa365282363808403cce4def191d7121538 Mon Sep 17 00:00:00 2001 From: Martin Tomka Date: Fri, 28 Jul 2023 07:38:23 +0200 Subject: [PATCH 2/2] pr comments --- .../CircuitBreaker/CircuitBreakerStrategyOptions.TResult.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Polly.Core/CircuitBreaker/CircuitBreakerStrategyOptions.TResult.cs b/src/Polly.Core/CircuitBreaker/CircuitBreakerStrategyOptions.TResult.cs index 15e1801a80..7f371beff8 100644 --- a/src/Polly.Core/CircuitBreaker/CircuitBreakerStrategyOptions.TResult.cs +++ b/src/Polly.Core/CircuitBreaker/CircuitBreakerStrategyOptions.TResult.cs @@ -23,7 +23,7 @@ namespace Polly.CircuitBreaker; public class CircuitBreakerStrategyOptions : ResilienceStrategyOptions { /// - /// Gets or sets the failure threshold at which the circuit will break. + /// Gets or sets the failure-to-success ratio at which the circuit will break. /// /// /// A number between zero and one (inclusive) e.g. 0.5 represents breaking if 50% or more of actions result in a handled failure.