Skip to content

Commit faa77a2

Browse files
committed
Cleanup OutcomeResilienceStrategy
1 parent 0cebeea commit faa77a2

15 files changed

+65
-109
lines changed

src/Polly.Core/CircuitBreaker/CircuitBreakerResilienceStrategy.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ public CircuitBreakerResilienceStrategy(
99
Func<OutcomeArguments<T, CircuitBreakerPredicateArguments>, ValueTask<bool>> handler,
1010
CircuitStateController<T> controller,
1111
CircuitBreakerStateProvider? stateProvider,
12-
CircuitBreakerManualControl? manualControl,
13-
bool isGeneric)
14-
: base(isGeneric)
12+
CircuitBreakerManualControl? manualControl)
1513
{
1614
_handler = handler;
1715
_controller = controller;
@@ -23,7 +21,7 @@ public CircuitBreakerResilienceStrategy(
2321
_controller.Dispose);
2422
}
2523

26-
protected override async ValueTask<Outcome<T>> ExecuteCallbackAsync<TState>(Func<ResilienceContext, TState, ValueTask<Outcome<T>>> callback, ResilienceContext context, TState state)
24+
protected override async ValueTask<Outcome<T>> ExecuteCore<TState>(Func<ResilienceContext, TState, ValueTask<Outcome<T>>> callback, ResilienceContext context, TState state)
2725
{
2826
if (await _controller.OnActionPreExecuteAsync(context).ConfigureAwait(context.ContinueOnCapturedContext) is Outcome<T> outcome)
2927
{

src/Polly.Core/CircuitBreaker/CircuitBreakerResilienceStrategyBuilderExtensions.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,7 @@ private static TBuilder AddSimpleCircuitBreakerCore<TBuilder, TResult>(this TBui
156156
options.ShouldHandle!,
157157
controller,
158158
options.StateProvider,
159-
options.ManualControl,
160-
context.IsGenericBuilder);
159+
options.ManualControl);
161160
}
162161
}
163162

src/Polly.Core/Fallback/FallbackResilienceStrategy.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,14 @@ internal sealed class FallbackResilienceStrategy<T> : OutcomeResilienceStrategy<
1010
private readonly Func<OutcomeArguments<T, OnFallbackArguments>, ValueTask>? _onFallback;
1111
private readonly ResilienceStrategyTelemetry _telemetry;
1212

13-
public FallbackResilienceStrategy(FallbackHandler<T> handler, Func<OutcomeArguments<T, OnFallbackArguments>, ValueTask>? onFallback, ResilienceStrategyTelemetry telemetry, bool isGeneric)
14-
: base(isGeneric)
13+
public FallbackResilienceStrategy(FallbackHandler<T> handler, Func<OutcomeArguments<T, OnFallbackArguments>, ValueTask>? onFallback, ResilienceStrategyTelemetry telemetry)
1514
{
1615
_handler = handler;
1716
_onFallback = onFallback;
1817
_telemetry = telemetry;
1918
}
2019

21-
protected override async ValueTask<Outcome<T>> ExecuteCallbackAsync<TState>(Func<ResilienceContext, TState, ValueTask<Outcome<T>>> callback, ResilienceContext context, TState state)
20+
protected override async ValueTask<Outcome<T>> ExecuteCore<TState>(Func<ResilienceContext, TState, ValueTask<Outcome<T>>> callback, ResilienceContext context, TState state)
2221
{
2322
var outcome = await ExecuteCallbackSafeAsync(callback, context, state).ConfigureAwait(context.ContinueOnCapturedContext);
2423
var handleFallbackArgs = new OutcomeArguments<T, FallbackPredicateArguments>(context, outcome, default);

src/Polly.Core/Fallback/FallbackResilienceStrategyBuilderExtensions.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,7 @@ internal static ResilienceStrategyBuilder AddFallback(this ResilienceStrategyBui
6262
return new FallbackResilienceStrategy<TResult>(
6363
handler,
6464
options.OnFallback,
65-
context.Telemetry,
66-
context.IsGenericBuilder);
65+
context.Telemetry);
6766
},
6867
options);
6968
}

src/Polly.Core/Hedging/HedgingResilienceStrategy.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,7 @@ public HedgingResilienceStrategy(
1717
Func<OutcomeArguments<T, OnHedgingArguments>, ValueTask>? onHedging,
1818
Func<HedgingDelayArguments, ValueTask<TimeSpan>>? hedgingDelayGenerator,
1919
TimeProvider timeProvider,
20-
ResilienceStrategyTelemetry telemetry,
21-
bool isGeneric)
22-
: base(isGeneric)
20+
ResilienceStrategyTelemetry telemetry)
2321
{
2422
HedgingDelay = hedgingDelay;
2523
MaxHedgedAttempts = maxHedgedAttempts;
@@ -43,7 +41,7 @@ public HedgingResilienceStrategy(
4341
public Func<OutcomeArguments<T, OnHedgingArguments>, ValueTask>? OnHedging { get; }
4442

4543
[ExcludeFromCodeCoverage] // coverlet issue
46-
protected override async ValueTask<Outcome<T>> ExecuteCallbackAsync<TState>(
44+
protected override async ValueTask<Outcome<T>> ExecuteCore<TState>(
4745
Func<ResilienceContext, TState, ValueTask<Outcome<T>>> callback,
4846
ResilienceContext context,
4947
TState state)

src/Polly.Core/Hedging/HedgingResilienceStrategyBuilderExtensions.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,7 @@ internal static ResilienceStrategyBuilder AddHedging(this ResilienceStrategyBuil
6767
options.OnHedging,
6868
options.HedgingDelayGenerator,
6969
context.TimeProvider,
70-
context.Telemetry,
71-
context.IsGenericBuilder);
70+
context.Telemetry);
7271
},
7372
options);
7473
}

src/Polly.Core/Retry/RetryResilienceStrategy.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,9 @@ internal sealed class RetryResilienceStrategy<T> : OutcomeResilienceStrategy<T>
1111

1212
public RetryResilienceStrategy(
1313
RetryStrategyOptions<T> options,
14-
bool isGeneric,
1514
TimeProvider timeProvider,
1615
ResilienceStrategyTelemetry telemetry,
1716
Func<double> randomizer)
18-
: base(isGeneric)
1917
{
2018
ShouldHandle = options.ShouldHandle;
2119
BaseDelay = options.BaseDelay;
@@ -41,7 +39,7 @@ public RetryResilienceStrategy(
4139

4240
public Func<OutcomeArguments<T, OnRetryArguments>, ValueTask>? OnRetry { get; }
4341

44-
protected override async ValueTask<Outcome<T>> ExecuteCallbackAsync<TState>(Func<ResilienceContext, TState, ValueTask<Outcome<T>>> callback, ResilienceContext context, TState state)
42+
protected override async ValueTask<Outcome<T>> ExecuteCore<TState>(Func<ResilienceContext, TState, ValueTask<Outcome<T>>> callback, ResilienceContext context, TState state)
4543
{
4644
double retryState = 0;
4745

src/Polly.Core/Retry/RetryResilienceStrategyBuilderExtensions.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ public static ResilienceStrategyBuilder<TResult> AddRetry<TResult>(this Resilien
5555
builder.AddStrategy(context =>
5656
new RetryResilienceStrategy<TResult>(
5757
options,
58-
context.IsGenericBuilder,
5958
context.TimeProvider,
6059
context.Telemetry,
6160
context.Randomizer),

src/Polly.Core/Utils/OutcomeResilienceStrategy.cs

Lines changed: 8 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -10,71 +10,41 @@
1010
/// </remarks>
1111
internal abstract class OutcomeResilienceStrategy<T> : ResilienceStrategy
1212
{
13-
private readonly bool _isGeneric;
14-
15-
protected OutcomeResilienceStrategy(bool isGeneric)
13+
protected OutcomeResilienceStrategy()
1614
{
17-
if (!isGeneric && typeof(T) != typeof(object))
18-
{
19-
throw new NotSupportedException("For non-generic strategies the generic parameter should be of type 'object'.");
20-
}
21-
22-
_isGeneric = isGeneric;
2315
}
2416

2517
protected internal sealed override ValueTask<Outcome<TResult>> ExecuteCore<TResult, TState>(
2618
Func<ResilienceContext, TState, ValueTask<Outcome<TResult>>> callback,
2719
ResilienceContext context,
2820
TState state)
2921
{
30-
if (_isGeneric)
22+
// Check if we can cast directly, thus saving some cycles and improving the performance
23+
if (context.ResultType == typeof(T))
3124
{
32-
if (typeof(TResult) != typeof(T))
33-
{
34-
return callback(context, state);
35-
}
36-
3725
// cast is safe here, because TResult and T are the same type
3826
var callbackCasted = (Func<ResilienceContext, TState, ValueTask<Outcome<T>>>)(object)callback;
39-
var valueTask = ExecuteCallbackAsync(callbackCasted, context, state);
27+
var valueTask = ExecuteCore(callbackCasted, context, state);
4028

41-
return ConvertValueTask<TResult>(valueTask, context);
29+
return TaskHelper.ConvertValueTask<T, TResult>(valueTask, context);
4230
}
4331
else
4432
{
45-
var valueTask = ExecuteCallbackAsync(
33+
var valueTask = ExecuteCore(
4634
static async (context, state) =>
4735
{
4836
var outcome = await state.callback(context, state.state).ConfigureAwait(context.ContinueOnCapturedContext);
49-
50-
// cast the outcome to "object" based on (T)
5137
return outcome.AsOutcome<T>();
5238
},
5339
context,
5440
(callback, state));
5541

56-
return ConvertValueTask<TResult>(valueTask, context);
42+
return TaskHelper.ConvertValueTask<T, TResult>(valueTask, context);
5743
}
5844
}
5945

60-
protected abstract ValueTask<Outcome<T>> ExecuteCallbackAsync<TState>(
46+
protected abstract ValueTask<Outcome<T>> ExecuteCore<TState>(
6147
Func<ResilienceContext, TState, ValueTask<Outcome<T>>> callback,
6248
ResilienceContext context,
6349
TState state);
64-
65-
private static ValueTask<Outcome<TResult>> ConvertValueTask<TResult>(ValueTask<Outcome<T>> valueTask, ResilienceContext resilienceContext)
66-
{
67-
if (valueTask.IsCompletedSuccessfully)
68-
{
69-
return new ValueTask<Outcome<TResult>>(valueTask.Result.AsOutcome<TResult>());
70-
}
71-
72-
return ConvertValueTaskAsync(valueTask, resilienceContext);
73-
74-
static async ValueTask<Outcome<TResult>> ConvertValueTaskAsync(ValueTask<Outcome<T>> valueTask, ResilienceContext resilienceContext)
75-
{
76-
var outcome = await valueTask.ConfigureAwait(resilienceContext.ContinueOnCapturedContext);
77-
return outcome.AsOutcome<TResult>();
78-
}
79-
}
8050
}

src/Polly.Core/Utils/TaskHelper.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System.Threading.Tasks;
2+
3+
namespace Polly.Utils;
4+
5+
internal static class TaskHelper
6+
{
7+
public static ValueTask<Outcome<TTo>> ConvertValueTask<TFrom, TTo>(ValueTask<Outcome<TFrom>> valueTask, ResilienceContext resilienceContext)
8+
{
9+
if (valueTask.IsCompletedSuccessfully)
10+
{
11+
return new ValueTask<Outcome<TTo>>(valueTask.Result.AsOutcome<TTo>());
12+
}
13+
14+
return ConvertValueTaskAsync(valueTask, resilienceContext);
15+
16+
static async ValueTask<Outcome<TTo>> ConvertValueTaskAsync(ValueTask<Outcome<TFrom>> valueTask, ResilienceContext resilienceContext)
17+
{
18+
var outcome = await valueTask.ConfigureAwait(resilienceContext.ContinueOnCapturedContext);
19+
return outcome.AsOutcome<TTo>();
20+
}
21+
}
22+
}

0 commit comments

Comments
 (0)