Skip to content

Commit dd511b2

Browse files
authored
Cleanup Outcome internals and drop unused hedging and fallbacks APIs (#1523)
1 parent 94db492 commit dd511b2

30 files changed

+129
-359
lines changed

src/Polly.Core/CircuitBreaker/CircuitBreakerResiliencePipelineBuilderExtensions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ internal static CircuitBreakerResilienceStrategy<TResult> CreateStrategy<TResult
7777
options.MinimumThroughput,
7878
HealthMetrics.Create(options.SamplingDuration, context.TimeProvider));
7979

80+
#pragma warning disable CA2000 // Dispose objects before losing scope
8081
var controller = new CircuitStateController<TResult>(
8182
options.BreakDuration,
8283
options.OnOpened,
@@ -85,6 +86,7 @@ internal static CircuitBreakerResilienceStrategy<TResult> CreateStrategy<TResult
8586
behavior,
8687
context.TimeProvider,
8788
context.Telemetry);
89+
#pragma warning restore CA2000 // Dispose objects before losing scope
8890

8991
return new CircuitBreakerResilienceStrategy<TResult>(
9092
options.ShouldHandle!,

src/Polly.Core/CircuitBreaker/CircuitBreakerResilienceStrategy.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public CircuitBreakerResilienceStrategy(
1515
_handler = handler;
1616
_controller = controller;
1717

18-
stateProvider?.Initialize(() => _controller.CircuitState, () => _controller.LastHandledOutcome);
18+
stateProvider?.Initialize(() => _controller.CircuitState);
1919
_manualControlRegistration = manualControl?.Initialize(
2020
async c => await _controller.IsolateCircuitAsync(c).ConfigureAwait(c.ContinueOnCapturedContext),
2121
async c => await _controller.CloseCircuitAsync(c).ConfigureAwait(c.ContinueOnCapturedContext));

src/Polly.Core/CircuitBreaker/CircuitBreakerStateProvider.cs

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,15 @@ namespace Polly.CircuitBreaker;
66
public sealed class CircuitBreakerStateProvider
77
{
88
private Func<CircuitState>? _circuitStateProvider;
9-
private Func<Outcome<object>?>? _lastHandledOutcomeProvider;
109

11-
internal void Initialize(Func<CircuitState> circuitStateProvider, Func<Outcome<object>?> lastHandledOutcomeProvider)
10+
internal void Initialize(Func<CircuitState> circuitStateProvider)
1211
{
1312
if (_circuitStateProvider != null)
1413
{
1514
throw new InvalidOperationException($"This instance of '{nameof(CircuitBreakerStateProvider)}' is already initialized and cannot be used in a different circuit-breaker strategy.");
1615
}
1716

1817
_circuitStateProvider = circuitStateProvider;
19-
_lastHandledOutcomeProvider = lastHandledOutcomeProvider;
2018
}
2119

2220
/// <summary>
@@ -32,11 +30,4 @@ internal void Initialize(Func<CircuitState> circuitStateProvider, Func<Outcome<o
3230
/// Gets the state of the underlying circuit.
3331
/// </summary>
3432
public CircuitState CircuitState => _circuitStateProvider?.Invoke() ?? CircuitState.Closed;
35-
36-
/// <summary>
37-
/// Gets the last outcome handled by the circuit-breaker.
38-
/// <remarks>
39-
/// This will be null if no exceptions or results have been handled by the circuit-breaker since the circuit last closed.</remarks>
40-
/// </summary>
41-
internal Outcome<object>? LastHandledOutcome => _lastHandledOutcomeProvider?.Invoke();
4233
}

src/Polly.Core/CircuitBreaker/Controller/CircuitStateController.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ internal sealed class CircuitStateController<T> : IDisposable
1818
private readonly TimeSpan _breakDuration;
1919
private DateTimeOffset _blockedUntil;
2020
private CircuitState _circuitState = CircuitState.Closed;
21-
private Outcome<object>? _lastOutcome;
21+
private Outcome<T>? _lastOutcome;
2222
private BrokenCircuitException _breakingException = new();
2323
private bool _disposed;
2424

@@ -66,7 +66,7 @@ public Exception? LastException
6666
}
6767
}
6868

69-
public Outcome<object>? LastHandledOutcome
69+
public Outcome<T>? LastHandledOutcome
7070
{
7171
get
7272
{
@@ -290,17 +290,17 @@ private bool PermitHalfOpenCircuitTest_NeedsLock()
290290
return false;
291291
}
292292

293-
private void SetLastHandledOutcome_NeedsLock<TResult>(Outcome<TResult> outcome)
293+
private void SetLastHandledOutcome_NeedsLock(Outcome<T> outcome)
294294
{
295-
_lastOutcome = outcome.AsOutcome();
295+
_lastOutcome = outcome;
296296

297297
if (outcome.Exception is Exception exception)
298298
{
299299
_breakingException = new BrokenCircuitException(BrokenCircuitException.DefaultMessage, exception);
300300
}
301301
else if (outcome.TryGetResult(out var result))
302302
{
303-
_breakingException = new BrokenCircuitException<TResult>(BrokenCircuitException.DefaultMessage, result!);
303+
_breakingException = new BrokenCircuitException<T>(BrokenCircuitException.DefaultMessage, result!);
304304
}
305305
}
306306

src/Polly.Core/Fallback/FallbackHandler.cs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,6 @@ internal sealed record class FallbackHandler<T>(
44
Func<FallbackPredicateArguments<T>, ValueTask<bool>> ShouldHandle,
55
Func<FallbackActionArguments<T>, ValueTask<Outcome<T>>> ActionGenerator)
66
{
7-
public async ValueTask<Outcome<TResult>> GetFallbackOutcomeAsync<TResult>(FallbackActionArguments<T> args)
8-
{
9-
var copiedArgs = new FallbackActionArguments<T>(
10-
args.Context,
11-
args.Outcome.AsOutcome<T>());
12-
13-
return (await ActionGenerator(copiedArgs).ConfigureAwait(args.Context.ContinueOnCapturedContext)).AsOutcome<TResult>();
14-
}
7+
public ValueTask<Outcome<T>> GetFallbackOutcomeAsync(FallbackActionArguments<T> args) => ActionGenerator(args);
158
}
169

src/Polly.Core/Fallback/FallbackResiliencePipelineBuilderExtensions.cs

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -32,27 +32,6 @@ public static class FallbackResiliencePipelineBuilderExtensions
3232
return builder.AddStrategy(context => CreateFallback(context, options), options);
3333
}
3434

35-
/// <summary>
36-
/// Adds a fallback resilience strategy with the provided options to the builder.
37-
/// </summary>
38-
/// <param name="builder">The resilience pipeline builder.</param>
39-
/// <param name="options">The options to configure the fallback resilience strategy.</param>
40-
/// <returns>The builder instance with the fallback strategy added.</returns>
41-
/// <exception cref="ArgumentNullException">Thrown when <paramref name="builder"/> or <paramref name="options"/> is <see langword="null"/>.</exception>
42-
/// <exception cref="ValidationException">Thrown when <paramref name="options"/> are invalid.</exception>
43-
[UnconditionalSuppressMessage(
44-
"Trimming",
45-
"IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code",
46-
Justification = "All options members preserved.")]
47-
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(FallbackStrategyOptions))]
48-
internal static ResiliencePipelineBuilder AddFallback(this ResiliencePipelineBuilder builder, FallbackStrategyOptions options)
49-
{
50-
Guard.NotNull(builder);
51-
Guard.NotNull(options);
52-
53-
return builder.AddStrategy(context => CreateFallback(context, options), options);
54-
}
55-
5635
private static ResilienceStrategy<TResult> CreateFallback<TResult>(
5736
StrategyBuilderContext context,
5837
FallbackStrategyOptions<TResult> options)

src/Polly.Core/Fallback/FallbackResilienceStrategy.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ protected internal override async ValueTask<Outcome<T>> ExecuteCore<TState>(Func
3737

3838
try
3939
{
40-
return await _handler.GetFallbackOutcomeAsync<T>(new FallbackActionArguments<T>(context, outcome)).ConfigureAwait(context.ContinueOnCapturedContext);
40+
return await _handler.GetFallbackOutcomeAsync(new FallbackActionArguments<T>(context, outcome)).ConfigureAwait(context.ContinueOnCapturedContext);
4141
}
4242
catch (Exception e)
4343
{

src/Polly.Core/Fallback/FallbackStrategyOptions.cs

Lines changed: 0 additions & 9 deletions
This file was deleted.

src/Polly.Core/Hedging/Controller/HedgingExecutionContext.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public async ValueTask<ExecutionInfo<T>> LoadExecutionAsync<TState>(
5555
{
5656
if (LoadedTasks >= _maxAttempts)
5757
{
58-
return CreateExecutionInfoWhenNoExecution<T>();
58+
return CreateExecutionInfoWhenNoExecution();
5959
}
6060

6161
// determine what type of task we are creating
@@ -77,7 +77,7 @@ public async ValueTask<ExecutionInfo<T>> LoadExecutionAsync<TState>(
7777
else
7878
{
7979
_executionPool.Return(execution);
80-
return CreateExecutionInfoWhenNoExecution<T>();
80+
return CreateExecutionInfoWhenNoExecution();
8181
}
8282
}
8383

@@ -148,17 +148,18 @@ public async ValueTask DisposeAsync()
148148
return TryRemoveExecutedTask();
149149
}
150150

151-
private ExecutionInfo<TResult> CreateExecutionInfoWhenNoExecution<TResult>()
151+
private ExecutionInfo<T> CreateExecutionInfoWhenNoExecution()
152152
{
153153
// if there are no more executing tasks we need to check finished ones
154154
if (_executingTasks.Count == 0)
155155
{
156156
var finishedExecution = _tasks.First(static t => t.ExecutionTaskSafe!.IsCompleted);
157157
finishedExecution.AcceptOutcome();
158-
return new ExecutionInfo<TResult>(null, false, finishedExecution.Outcome.AsOutcome<TResult>());
158+
159+
return new ExecutionInfo<T>(null, false, finishedExecution.Outcome);
159160
}
160161

161-
return new ExecutionInfo<TResult>(null, false, null);
162+
return new ExecutionInfo<T>(null, false, null);
162163
}
163164

164165
private Task<Task> WaitForTaskCompetitionAsync()

src/Polly.Core/Hedging/Controller/HedgingHandler.cs

Lines changed: 7 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,44 +2,17 @@ namespace Polly.Hedging.Utils;
22

33
internal sealed record class HedgingHandler<T>(
44
Func<HedgingPredicateArguments<T>, ValueTask<bool>> ShouldHandle,
5-
Func<HedgingActionGeneratorArguments<T>, Func<ValueTask<Outcome<T>>>?> ActionGenerator,
6-
bool IsGeneric)
5+
Func<HedgingActionGeneratorArguments<T>, Func<ValueTask<Outcome<T>>>?> ActionGenerator)
76
{
87
public Func<ValueTask<Outcome<T>>>? GenerateAction(HedgingActionGeneratorArguments<T> args)
98
{
10-
if (IsGeneric)
11-
{
12-
var copiedArgs = new HedgingActionGeneratorArguments<T>(
13-
args.PrimaryContext,
14-
args.ActionContext,
15-
args.AttemptNumber,
16-
args.Callback);
9+
var copiedArgs = new HedgingActionGeneratorArguments<T>(
10+
args.PrimaryContext,
11+
args.ActionContext,
12+
args.AttemptNumber,
13+
args.Callback);
1714

18-
return ActionGenerator(copiedArgs);
19-
}
20-
21-
return CreateNonGenericAction(args);
22-
}
23-
24-
private Func<ValueTask<Outcome<T>>>? CreateNonGenericAction(HedgingActionGeneratorArguments<T> args)
25-
{
26-
var generator = (Func<HedgingActionGeneratorArguments<object>, Func<ValueTask<Outcome<object>>>?>)(object)ActionGenerator;
27-
var action = generator(new HedgingActionGeneratorArguments<object>(args.PrimaryContext, args.ActionContext, args.AttemptNumber, async context =>
28-
{
29-
var outcome = await args.Callback(context).ConfigureAwait(context.ContinueOnCapturedContext);
30-
return outcome.AsOutcome();
31-
}));
32-
33-
if (action is null)
34-
{
35-
return null;
36-
}
37-
38-
return async () =>
39-
{
40-
var outcome = await action().ConfigureAwait(args.ActionContext.ContinueOnCapturedContext);
41-
return outcome.AsOutcome<T>();
42-
};
15+
return ActionGenerator(copiedArgs);
4316
}
4417
}
4518

0 commit comments

Comments
 (0)