Skip to content

Commit 37318c4

Browse files
committed
Drop object-based outcome conversions
1 parent 7dfc250 commit 37318c4

14 files changed

+26
-79
lines changed

src/Polly.Core/CircuitBreaker/CircuitBreakerResiliencePipelineBuilderExtensions.cs

+2
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

+1-1
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

+1-10
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

+5-5
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.ToObjectOutcome(outcome);
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/Hedging/Controller/HedgingExecutionContext.cs

+1-3
Original file line numberDiff line numberDiff line change
@@ -156,9 +156,7 @@ private ExecutionInfo<T> CreateExecutionInfoWhenNoExecution()
156156
var finishedExecution = _tasks.First(static t => t.ExecutionTaskSafe!.IsCompleted);
157157
finishedExecution.AcceptOutcome();
158158

159-
var outcome = Outcome.FromObjectOutcome<T>(finishedExecution.Outcome);
160-
161-
return new ExecutionInfo<T>(null, false, outcome);
159+
return new ExecutionInfo<T>(null, false, finishedExecution.Outcome);
162160
}
163161

164162
return new ExecutionInfo<T>(null, false, null);

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public TaskExecution(HedgingHandler<T> handler, CancellationTokenSourcePool canc
4949
/// </remarks>
5050
public Task? ExecutionTaskSafe { get; private set; }
5151

52-
public Outcome<object> Outcome { get; private set; }
52+
public Outcome<T> Outcome { get; private set; }
5353

5454
public bool IsHandled { get; private set; }
5555

@@ -225,7 +225,7 @@ private async Task ExecutePrimaryActionAsync<TState>(Func<ResilienceContext, TSt
225225
private async Task UpdateOutcomeAsync(Outcome<T> outcome)
226226
{
227227
var args = new HedgingPredicateArguments<T>(Context, outcome);
228-
Outcome = Polly.Outcome.ToObjectOutcome(outcome);
228+
Outcome = outcome;
229229
IsHandled = await _handler.ShouldHandle(args).ConfigureAwait(Context.ContinueOnCapturedContext);
230230
TelemetryUtil.ReportExecutionAttempt(_telemetry, Context, outcome, AttemptNumber, ExecutionTime, IsHandled);
231231
}

src/Polly.Core/Hedging/HedgingResilienceStrategy.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ await HandleOnHedgingAsync(
9999
continue;
100100
}
101101

102-
outcome = Outcome.FromObjectOutcome<T>(execution.Outcome);
102+
outcome = execution.Outcome;
103103

104104
if (!execution.IsHandled)
105105
{

src/Polly.Core/Outcome.cs

-20
Original file line numberDiff line numberDiff line change
@@ -52,24 +52,4 @@ public static ValueTask<Outcome<TResult>> FromExceptionAsTask<TResult>(Exception
5252
internal static Outcome<VoidResult> Void => FromResult(VoidResult.Instance);
5353

5454
internal static Outcome<VoidResult> FromException(Exception exception) => FromException<VoidResult>(exception);
55-
56-
internal static Outcome<object> ToObjectOutcome<T>(Outcome<T> outcome)
57-
{
58-
if (outcome.ExceptionDispatchInfo is null)
59-
{
60-
return FromResult((object?)outcome.Result);
61-
}
62-
63-
return new Outcome<object>(outcome.ExceptionDispatchInfo);
64-
}
65-
66-
internal static Outcome<T> FromObjectOutcome<T>(Outcome<object> outcome)
67-
{
68-
if (outcome.ExceptionDispatchInfo is null)
69-
{
70-
return FromResult((T)outcome.Result!);
71-
}
72-
73-
return new Outcome<T>(outcome.ExceptionDispatchInfo);
74-
}
7555
}

test/Polly.Core.Tests/CircuitBreaker/CircuitBreakerResilienceStrategyTests.cs

-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ public void Ctor_StateProvider_EnsureAttached()
4444
_options.StateProvider.IsInitialized.Should().BeTrue();
4545

4646
_options.StateProvider.CircuitState.Should().Be(CircuitState.Closed);
47-
_options.StateProvider.LastHandledOutcome.Should().Be(null);
4847
}
4948

5049
[Fact]

test/Polly.Core.Tests/CircuitBreaker/CircuitBreakerStateProviderTests.cs

+2-11
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ public void NotInitialized_EnsureDefaults()
1818
var provider = new CircuitBreakerStateProvider();
1919

2020
provider.CircuitState.Should().Be(CircuitState.Closed);
21-
provider.LastHandledOutcome.Should().Be(null);
2221
}
2322

2423
[Fact]
@@ -36,10 +35,10 @@ await control
3635
public void Initialize_Twice_Throws()
3736
{
3837
var provider = new CircuitBreakerStateProvider();
39-
provider.Initialize(() => CircuitState.Closed, () => null);
38+
provider.Initialize(() => CircuitState.Closed);
4039

4140
provider
42-
.Invoking(c => c.Initialize(() => CircuitState.Closed, () => null))
41+
.Invoking(c => c.Initialize(() => CircuitState.Closed))
4342
.Should()
4443
.Throw<InvalidOperationException>();
4544
}
@@ -49,24 +48,16 @@ public void Initialize_Ok()
4948
{
5049
var provider = new CircuitBreakerStateProvider();
5150
var stateCalled = false;
52-
var exceptionCalled = false;
5351

5452
provider.Initialize(
5553
() =>
5654
{
5755
stateCalled = true;
5856
return CircuitState.HalfOpen;
59-
},
60-
() =>
61-
{
62-
exceptionCalled = true;
63-
return Outcome.FromException<object>(new InvalidOperationException());
6457
});
6558

6659
provider.CircuitState.Should().Be(CircuitState.HalfOpen);
67-
provider.LastHandledOutcome!.Value.Exception.Should().BeOfType<InvalidOperationException>();
6860

6961
stateCalled.Should().BeTrue();
70-
exceptionCalled.Should().BeTrue();
7162
}
7263
}

test/Polly.Core.Tests/Hedging/Controller/HedgingExecutionContextTests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ public async Task TryWaitForCompletedExecutionAsync_FinishedTask_Ok()
104104
task.Should().NotBeNull();
105105
task!.ExecutionTaskSafe!.IsCompleted.Should().BeTrue();
106106

107-
Outcome.FromObjectOutcome<DisposableResult>(task.Outcome).Result!.Name.Should().Be("dummy");
107+
task.Outcome.Result!.Name.Should().Be("dummy");
108108
task.AcceptOutcome();
109109
context.LoadedTasks.Should().Be(1);
110110
}

test/Polly.Core.Tests/Hedging/Controller/TaskExecutionTests.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ await execution.InitializeAsync(HedgedTaskType.Primary, _snapshot,
5858
99);
5959

6060
await execution.ExecutionTaskSafe!;
61-
((DisposableResult)execution.Outcome.Result!).Name.Should().Be(value);
61+
execution.Outcome.Result!.Name.Should().Be(value);
6262
execution.IsHandled.Should().Be(handled);
6363
AssertPrimaryContext(execution.Context, execution);
6464

@@ -98,7 +98,7 @@ public async Task Initialize_Secondary_Ok(string value, bool handled)
9898

9999
await execution.ExecutionTaskSafe!;
100100

101-
((DisposableResult)execution.Outcome.Result!).Name.Should().Be(value);
101+
execution.Outcome.Result!.Name.Should().Be(value);
102102
execution.IsHandled.Should().Be(handled);
103103
AssertSecondaryContext(execution.Context, execution);
104104
}

test/Polly.Core.Tests/OutcomeTests.cs

-21
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,6 @@ public void Ctor_Result_Ok()
1212
outcome.TryGetResult(out var result).Should().BeTrue();
1313
result.Should().Be(10);
1414
outcome.ToString().Should().Be("10");
15-
16-
var objectOutcome = Outcome.ToObjectOutcome(outcome);
17-
objectOutcome.HasResult.Should().BeTrue();
18-
objectOutcome.Exception.Should().BeNull();
19-
objectOutcome.IsVoidResult.Should().BeFalse();
20-
objectOutcome.TryGetResult(out var resultObj).Should().BeTrue();
21-
resultObj.Should().Be(10);
2215
}
2316

2417
[Fact]
@@ -31,13 +24,6 @@ public void Ctor_VoidResult_Ok()
3124
outcome.TryGetResult(out var result).Should().BeFalse();
3225
outcome.Result.Should().Be(VoidResult.Instance);
3326
outcome.ToString().Should().Be("void");
34-
35-
var objectOutcome = Outcome.ToObjectOutcome(outcome);
36-
objectOutcome.HasResult.Should().BeTrue();
37-
objectOutcome.Exception.Should().BeNull();
38-
objectOutcome.IsVoidResult.Should().BeTrue();
39-
objectOutcome.TryGetResult(out _).Should().BeFalse();
40-
objectOutcome.Result.Should().Be(VoidResult.Instance);
4127
}
4228

4329
[Fact]
@@ -50,13 +36,6 @@ public void Ctor_Exception_Ok()
5036
outcome.IsVoidResult.Should().BeFalse();
5137
outcome.TryGetResult(out var result).Should().BeFalse();
5238
outcome.ToString().Should().Be("Dummy message.");
53-
54-
var objectOutcome = Outcome.ToObjectOutcome(outcome);
55-
objectOutcome.HasResult.Should().BeFalse();
56-
objectOutcome.Exception.Should().NotBeNull();
57-
objectOutcome.IsVoidResult.Should().BeFalse();
58-
objectOutcome.TryGetResult(out _).Should().BeFalse();
59-
objectOutcome.ExceptionDispatchInfo.Should().Be(outcome.ExceptionDispatchInfo);
6039
}
6140

6241
[Fact]

test/Polly.TestUtils/TestUtilities.cs

+8-1
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,18 @@ public static ResilienceContext WithVoidResultType(this ResilienceContext contex
9999

100100
public static TelemetryEventArguments<object, object> AsObjectArguments<T, TArgs>(this TelemetryEventArguments<T, TArgs> args)
101101
{
102+
Outcome<object>? outcome = args.Outcome switch
103+
{
104+
null => null,
105+
{ Exception: { } ex } => Outcome.FromException<object>(ex),
106+
_ => Outcome.FromResult<object>(args.Outcome!.Value.Result),
107+
};
108+
102109
return new TelemetryEventArguments<object, object>(
103110
args.Source,
104111
args.Event,
105112
args.Context,
106113
args.Arguments!,
107-
args.Outcome.HasValue ? Outcome.ToObjectOutcome(args.Outcome.Value) : null);
114+
outcome);
108115
}
109116
}

0 commit comments

Comments
 (0)