From 4153d2a4947df4fcd7d262d9bb0dceb6612fce53 Mon Sep 17 00:00:00 2001
From: martintmk <103487740+martintmk@users.noreply.github.com>
Date: Tue, 8 Aug 2023 11:41:39 +0200
Subject: [PATCH] Make the `ReactiveResilienceStrategy` type-safe (#1462)
---
...eakerCompositeStrategyBuilderExtensions.cs | 43 ++++++--------
.../CircuitBreakerResilienceStrategy.cs | 2 +-
.../CompositeStrategyBuilderExtensions.cs | 47 +++++++++++++++
...lbackCompositeStrategyBuilderExtensions.cs | 45 +++++++-------
.../Fallback/FallbackResilienceStrategy.cs | 2 +-
...dgingCompositeStrategyBuilderExtensions.cs | 58 ++++++++++---------
.../Hedging/HedgingResilienceStrategy.cs | 2 +-
src/Polly.Core/PublicAPI.Unshipped.txt | 9 +--
src/Polly.Core/ReactiveResilienceStrategy.cs | 37 +++---------
src/Polly.Core/ResilienceStrategy.cs | 35 +----------
...RetryCompositeStrategyBuilderExtensions.cs | 34 +++++------
.../Retry/RetryResilienceStrategy.cs | 2 +-
.../Utils/ReactiveResilienceStrategyBridge.cs | 35 +++++++++++
src/Polly.Core/Utils/StrategyHelper.cs | 44 ++++++++++++++
.../ResilienceStrategyExtensions.cs | 19 +++++-
...uitBreakerCompositeStrategyBuilderTests.cs | 11 +++-
.../CircuitBreakerResilienceStrategyTests.cs | 3 +-
.../CompositeStrategyBuilderTests.cs | 10 +++-
...CompositeStrategyBuilderExtensionsTests.cs | 7 ++-
.../FallbackResilienceStrategyTests.cs | 5 +-
...CompositeStrategyBuilderExtensionsTests.cs | 13 ++++-
.../Hedging/HedgingResilienceStrategyTests.cs | 11 ++--
...CompositeStrategyBuilderExtensionsTests.cs | 5 +-
.../Retry/RetryResilienceStrategyTests.cs | 9 +--
... ReactiveResilienceStrategyBridgeTests.cs} | 20 ++++---
.../ResilienceStrategyExtensionsTests.cs | 44 +++++++++++++-
26 files changed, 354 insertions(+), 198 deletions(-)
create mode 100644 src/Polly.Core/Utils/ReactiveResilienceStrategyBridge.cs
create mode 100644 src/Polly.Core/Utils/StrategyHelper.cs
rename test/Polly.Core.Tests/Utils/{ReactiveResilienceStrategyTests.cs => ReactiveResilienceStrategyBridgeTests.cs} (69%)
diff --git a/src/Polly.Core/CircuitBreaker/CircuitBreakerCompositeStrategyBuilderExtensions.cs b/src/Polly.Core/CircuitBreaker/CircuitBreakerCompositeStrategyBuilderExtensions.cs
index a7f02bcac3c..281e7845cd8 100644
--- a/src/Polly.Core/CircuitBreaker/CircuitBreakerCompositeStrategyBuilderExtensions.cs
+++ b/src/Polly.Core/CircuitBreaker/CircuitBreakerCompositeStrategyBuilderExtensions.cs
@@ -24,12 +24,17 @@ public static class CircuitBreakerCompositeStrategyBuilderExtensions
///
/// Thrown when or is .
/// Thrown when are invalid.
+ [UnconditionalSuppressMessage(
+ "Trimming",
+ "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code",
+ Justification = "All options members preserved.")]
+ [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(CircuitBreakerStrategyOptions))]
public static CompositeStrategyBuilder AddCircuitBreaker(this CompositeStrategyBuilder builder, CircuitBreakerStrategyOptions options)
{
Guard.NotNull(builder);
Guard.NotNull(options);
- return builder.AddCircuitBreakerCore(options);
+ return builder.AddStrategy(context => CreateStrategy(context, options), options);
}
///
@@ -47,39 +52,29 @@ public static CompositeStrategyBuilder AddCircuitBreaker(this CompositeStrategyB
///
/// Thrown when or is .
/// Thrown when are invalid.
- public static CompositeStrategyBuilder AddCircuitBreaker(this CompositeStrategyBuilder builder, CircuitBreakerStrategyOptions options)
- {
- Guard.NotNull(builder);
- Guard.NotNull(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 AddCircuitBreakerCore(this TBuilder builder, CircuitBreakerStrategyOptions options)
- where TBuilder : CompositeStrategyBuilderBase
+ public static CompositeStrategyBuilder AddCircuitBreaker<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TResult>(
+ this CompositeStrategyBuilder builder,
+ CircuitBreakerStrategyOptions options)
{
- return builder.AddStrategy(
- context =>
- {
- var behavior = new AdvancedCircuitBehavior(
- options.FailureRatio,
- options.MinimumThroughput,
- HealthMetrics.Create(options.SamplingDuration, context.TimeProvider));
+ Guard.NotNull(builder);
+ Guard.NotNull(options);
- return CreateStrategy>(context, options, behavior);
- },
- options);
+ return builder.AddStrategy(context => CreateStrategy(context, options), options);
}
- internal static CircuitBreakerResilienceStrategy CreateStrategy(
+ internal static CircuitBreakerResilienceStrategy CreateStrategy(
StrategyBuilderContext context,
- CircuitBreakerStrategyOptions options,
- CircuitBehavior behavior)
+ CircuitBreakerStrategyOptions options)
{
+ var behavior = new AdvancedCircuitBehavior(
+ options.FailureRatio,
+ options.MinimumThroughput,
+ HealthMetrics.Create(options.SamplingDuration, context.TimeProvider));
+
var controller = new CircuitStateController(
options.BreakDuration,
options.OnOpened,
diff --git a/src/Polly.Core/CircuitBreaker/CircuitBreakerResilienceStrategy.cs b/src/Polly.Core/CircuitBreaker/CircuitBreakerResilienceStrategy.cs
index 716931863c9..f564c86aa01 100644
--- a/src/Polly.Core/CircuitBreaker/CircuitBreakerResilienceStrategy.cs
+++ b/src/Polly.Core/CircuitBreaker/CircuitBreakerResilienceStrategy.cs
@@ -21,7 +21,7 @@ public CircuitBreakerResilienceStrategy(
_controller.Dispose);
}
- protected override async ValueTask> ExecuteCore(Func>> callback, ResilienceContext context, TState state)
+ protected internal override async ValueTask> ExecuteCore(Func>> callback, ResilienceContext context, TState state)
{
if (await _controller.OnActionPreExecuteAsync(context).ConfigureAwait(context.ContinueOnCapturedContext) is Outcome outcome)
{
diff --git a/src/Polly.Core/CompositeStrategyBuilderExtensions.cs b/src/Polly.Core/CompositeStrategyBuilderExtensions.cs
index 0986ae01bda..a55625d9c6f 100644
--- a/src/Polly.Core/CompositeStrategyBuilderExtensions.cs
+++ b/src/Polly.Core/CompositeStrategyBuilderExtensions.cs
@@ -70,6 +70,53 @@ public static TBuilder AddStrategy(this TBuilder builder, Func
+ /// Adds a reactive strategy to the builder.
+ ///
+ /// The builder instance.
+ /// The factory that creates a resilience strategy.
+ /// The options associated with the strategy. If none are provided the default instance of is created.
+ /// The same builder instance.
+ /// Thrown when , or is .
+ /// Thrown when this builder was already used to create a strategy. The builder cannot be modified after it has been used.
+ /// Thrown when is invalid.
+ [RequiresUnreferencedCode(Constants.OptionsValidation)]
+ public static CompositeStrategyBuilder AddStrategy(
+ this CompositeStrategyBuilder builder, Func> factory,
+ ResilienceStrategyOptions options)
+ {
+ Guard.NotNull(builder);
+ Guard.NotNull(factory);
+ Guard.NotNull(options);
+
+ builder.AddStrategyCore(context => new ReactiveResilienceStrategyBridge