From 3bdcafbaa829994b5b6739ba8091408727bfdab8 Mon Sep 17 00:00:00 2001 From: peter-csala Date: Tue, 16 Jul 2024 10:47:27 +0200 Subject: [PATCH] Add outcome to the break duration generator arguments --- .../BreakDurationGeneratorArguments.cs | 26 ++++++++++++------- .../CircuitBreakerStrategyOptions.TResult.cs | 2 +- .../Controller/CircuitStateController.cs | 6 ++--- src/Polly.Core/PublicAPI.Shipped.txt | 19 +++++++------- .../BreakDurationGeneratorArgumentsTests.cs | 8 ++++-- 5 files changed, 37 insertions(+), 24 deletions(-) diff --git a/src/Polly.Core/CircuitBreaker/BreakDurationGeneratorArguments.cs b/src/Polly.Core/CircuitBreaker/BreakDurationGeneratorArguments.cs index 8883f6dd77..a16f854753 100644 --- a/src/Polly.Core/CircuitBreaker/BreakDurationGeneratorArguments.cs +++ b/src/Polly.Core/CircuitBreaker/BreakDurationGeneratorArguments.cs @@ -7,10 +7,11 @@ namespace Polly.CircuitBreaker; /// /// Represents arguments used to generate a dynamic break duration for a circuit breaker. /// -public readonly struct BreakDurationGeneratorArguments +/// The type of result. +public readonly struct BreakDurationGeneratorArguments { /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The failure rate at which the circuit breaker should trip. /// It represents the ratio of failed actions to the total executed actions. @@ -18,20 +19,19 @@ public readonly struct BreakDurationGeneratorArguments /// This count is used to determine if the failure threshold has been reached. /// The resilience context providing additional information /// about the execution state and failures. + /// The outcome of the resilience operation or event. [EditorBrowsable(EditorBrowsableState.Never)] public BreakDurationGeneratorArguments( double failureRate, int failureCount, - ResilienceContext context) + ResilienceContext context, + Outcome outcome) + : this(failureRate, failureCount, context, 0, outcome) { - FailureRate = failureRate; - FailureCount = failureCount; - Context = context; - HalfOpenAttempts = 0; } /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The failure rate at which the circuit breaker should trip. /// It represents the ratio of failed actions to the total executed actions. @@ -40,16 +40,19 @@ public BreakDurationGeneratorArguments( /// The resilience context providing additional information /// about the execution state and failures. /// The number of half-open attempts. + /// The outcome of the resilience operation or event. public BreakDurationGeneratorArguments( double failureRate, int failureCount, ResilienceContext context, - int halfOpenAttempts) + int halfOpenAttempts, + Outcome outcome) { FailureRate = failureRate; FailureCount = failureCount; Context = context; HalfOpenAttempts = halfOpenAttempts; + Outcome = outcome; } /// @@ -71,4 +74,9 @@ public BreakDurationGeneratorArguments( /// Gets the number of half-open attempts. /// public int HalfOpenAttempts { get; } + + /// + /// Gets the outcome of the user-specified callback. + /// + public Outcome Outcome { get; } } diff --git a/src/Polly.Core/CircuitBreaker/CircuitBreakerStrategyOptions.TResult.cs b/src/Polly.Core/CircuitBreaker/CircuitBreakerStrategyOptions.TResult.cs index 8d1bdbdeec..d867158a4e 100644 --- a/src/Polly.Core/CircuitBreaker/CircuitBreakerStrategyOptions.TResult.cs +++ b/src/Polly.Core/CircuitBreaker/CircuitBreakerStrategyOptions.TResult.cs @@ -75,7 +75,7 @@ public class CircuitBreakerStrategyOptions : ResilienceStrategyOptions /// /// The default value is . /// - public Func>? BreakDurationGenerator { get; set; } + public Func, ValueTask>? BreakDurationGenerator { get; set; } /// /// Gets or sets a predicate that determines whether the outcome should be handled by the circuit breaker. diff --git a/src/Polly.Core/CircuitBreaker/Controller/CircuitStateController.cs b/src/Polly.Core/CircuitBreaker/Controller/CircuitStateController.cs index 40dd2c5e35..8cfcfc9573 100644 --- a/src/Polly.Core/CircuitBreaker/Controller/CircuitStateController.cs +++ b/src/Polly.Core/CircuitBreaker/Controller/CircuitStateController.cs @@ -16,7 +16,7 @@ internal sealed class CircuitStateController : IDisposable private readonly ResilienceStrategyTelemetry _telemetry; private readonly CircuitBehavior _behavior; private readonly TimeSpan _breakDuration; - private readonly Func>? _breakDurationGenerator; + private readonly Func, ValueTask>? _breakDurationGenerator; private DateTimeOffset _blockedUntil; private CircuitState _circuitState = CircuitState.Closed; private Outcome? _lastOutcome; @@ -33,7 +33,7 @@ public CircuitStateController( CircuitBehavior behavior, TimeProvider timeProvider, ResilienceStrategyTelemetry telemetry, - Func>? breakDurationGenerator) + Func, ValueTask>? breakDurationGenerator) #pragma warning restore S107 { _breakDuration = breakDuration; @@ -323,7 +323,7 @@ private void OpenCircuitFor_NeedsLock(Outcome outcome, TimeSpan breakDuration { #pragma warning disable CA2012 #pragma warning disable S1226 - breakDuration = _breakDurationGenerator(new(_behavior.FailureRate, _behavior.FailureCount, context, _halfOpenAttempts)).GetAwaiter().GetResult(); + breakDuration = _breakDurationGenerator(new(_behavior.FailureRate, _behavior.FailureCount, context, _halfOpenAttempts, outcome)).GetAwaiter().GetResult(); #pragma warning restore S1226 #pragma warning restore CA2012 } diff --git a/src/Polly.Core/PublicAPI.Shipped.txt b/src/Polly.Core/PublicAPI.Shipped.txt index 0815ba16d1..aba24b3099 100644 --- a/src/Polly.Core/PublicAPI.Shipped.txt +++ b/src/Polly.Core/PublicAPI.Shipped.txt @@ -11,14 +11,15 @@ override Polly.Registry.ResiliencePipelineRegistry.TryGetPipeline(TKey key override Polly.Registry.ResiliencePipelineRegistry.TryGetPipeline(TKey key, out Polly.ResiliencePipeline? pipeline) -> bool override Polly.ResiliencePropertyKey.ToString() -> string! override Polly.Telemetry.ResilienceEvent.ToString() -> string! -Polly.CircuitBreaker.BreakDurationGeneratorArguments -Polly.CircuitBreaker.BreakDurationGeneratorArguments.BreakDurationGeneratorArguments() -> void -Polly.CircuitBreaker.BreakDurationGeneratorArguments.BreakDurationGeneratorArguments(double failureRate, int failureCount, Polly.ResilienceContext! context) -> void -Polly.CircuitBreaker.BreakDurationGeneratorArguments.BreakDurationGeneratorArguments(double failureRate, int failureCount, Polly.ResilienceContext! context, int halfOpenAttempts) -> void -Polly.CircuitBreaker.BreakDurationGeneratorArguments.Context.get -> Polly.ResilienceContext! -Polly.CircuitBreaker.BreakDurationGeneratorArguments.FailureCount.get -> int -Polly.CircuitBreaker.BreakDurationGeneratorArguments.FailureRate.get -> double -Polly.CircuitBreaker.BreakDurationGeneratorArguments.HalfOpenAttempts.get -> int +Polly.CircuitBreaker.BreakDurationGeneratorArguments +Polly.CircuitBreaker.BreakDurationGeneratorArguments.BreakDurationGeneratorArguments() -> void +Polly.CircuitBreaker.BreakDurationGeneratorArguments.BreakDurationGeneratorArguments(double failureRate, int failureCount, Polly.ResilienceContext! context, Polly.Outcome outcome) -> void +Polly.CircuitBreaker.BreakDurationGeneratorArguments.BreakDurationGeneratorArguments(double failureRate, int failureCount, Polly.ResilienceContext! context, int halfOpenAttempts, Polly.Outcome outcome) -> void +Polly.CircuitBreaker.BreakDurationGeneratorArguments.Context.get -> Polly.ResilienceContext! +Polly.CircuitBreaker.BreakDurationGeneratorArguments.FailureCount.get -> int +Polly.CircuitBreaker.BreakDurationGeneratorArguments.FailureRate.get -> double +Polly.CircuitBreaker.BreakDurationGeneratorArguments.HalfOpenAttempts.get -> int +Polly.CircuitBreaker.BreakDurationGeneratorArguments.Outcome.get -> Polly.Outcome Polly.CircuitBreaker.BrokenCircuitException Polly.CircuitBreaker.BrokenCircuitException.BrokenCircuitException() -> void Polly.CircuitBreaker.BrokenCircuitException.BrokenCircuitException(string! message) -> void @@ -41,7 +42,7 @@ Polly.CircuitBreaker.CircuitBreakerStrategyOptions.CircuitBreakerStrategyOptions Polly.CircuitBreaker.CircuitBreakerStrategyOptions Polly.CircuitBreaker.CircuitBreakerStrategyOptions.BreakDuration.get -> System.TimeSpan Polly.CircuitBreaker.CircuitBreakerStrategyOptions.BreakDuration.set -> void -Polly.CircuitBreaker.CircuitBreakerStrategyOptions.BreakDurationGenerator.get -> System.Func>? +Polly.CircuitBreaker.CircuitBreakerStrategyOptions.BreakDurationGenerator.get -> System.Func, System.Threading.Tasks.ValueTask>? Polly.CircuitBreaker.CircuitBreakerStrategyOptions.BreakDurationGenerator.set -> void Polly.CircuitBreaker.CircuitBreakerStrategyOptions.CircuitBreakerStrategyOptions() -> void Polly.CircuitBreaker.CircuitBreakerStrategyOptions.FailureRatio.get -> double diff --git a/test/Polly.Core.Tests/CircuitBreaker/BreakDurationGeneratorArgumentsTests.cs b/test/Polly.Core.Tests/CircuitBreaker/BreakDurationGeneratorArgumentsTests.cs index 7b0e537855..6cf9cf1002 100644 --- a/test/Polly.Core.Tests/CircuitBreaker/BreakDurationGeneratorArgumentsTests.cs +++ b/test/Polly.Core.Tests/CircuitBreaker/BreakDurationGeneratorArgumentsTests.cs @@ -11,12 +11,14 @@ public void Constructor_Old_Ok() double expectedFailureRate = 0.5; int failureCount = 10; var context = new ResilienceContext(); + var outcome = Outcome.FromResult(42); - var args = new BreakDurationGeneratorArguments(expectedFailureRate, failureCount, context); + var args = new BreakDurationGeneratorArguments(expectedFailureRate, failureCount, context, outcome); args.FailureRate.Should().Be(expectedFailureRate); args.FailureCount.Should().Be(failureCount); args.Context.Should().Be(context); + args.Outcome.Should().Be(outcome); } [Fact] @@ -25,12 +27,14 @@ public void Constructor_Ok() double expectedFailureRate = 0.5; int failureCount = 10; var context = new ResilienceContext(); + var outcome = Outcome.FromResult(42); - var args = new BreakDurationGeneratorArguments(expectedFailureRate, failureCount, context, 99); + var args = new BreakDurationGeneratorArguments(expectedFailureRate, failureCount, context, 99, outcome); args.FailureRate.Should().Be(expectedFailureRate); args.FailureCount.Should().Be(failureCount); args.Context.Should().Be(context); args.HalfOpenAttempts.Should().Be(99); + args.Outcome.Should().Be(outcome); } }