diff --git a/src/Polly.Specs/Bulkhead/BulkheadAsyncSpecs.cs b/src/Polly.Specs/Bulkhead/BulkheadAsyncSpecs.cs index 31310a39b52..140548862ab 100644 --- a/src/Polly.Specs/Bulkhead/BulkheadAsyncSpecs.cs +++ b/src/Polly.Specs/Bulkhead/BulkheadAsyncSpecs.cs @@ -5,7 +5,7 @@ using Polly.Specs.Helpers.Bulkhead; using FluentAssertions; -using Polly.Utilities; +using Polly.Specs.Helpers; using Xunit; using Xunit.Abstractions; diff --git a/src/Polly.Specs/Bulkhead/BulkheadTResultAsyncSpecs.cs b/src/Polly.Specs/Bulkhead/BulkheadTResultAsyncSpecs.cs index 4fffd2fbd5d..e9dbca9ab10 100644 --- a/src/Polly.Specs/Bulkhead/BulkheadTResultAsyncSpecs.cs +++ b/src/Polly.Specs/Bulkhead/BulkheadTResultAsyncSpecs.cs @@ -5,7 +5,6 @@ using Polly.Specs.Helpers; using Polly.Specs.Helpers.Bulkhead; using FluentAssertions; -using Polly.Utilities; using Xunit; using Xunit.Abstractions; diff --git a/src/Polly.Specs/Executables/ExecutablesAsyncSpecs.cs b/src/Polly.Specs/Executables/ExecutablesAsyncSpecs.cs new file mode 100644 index 00000000000..6ae055db6ad --- /dev/null +++ b/src/Polly.Specs/Executables/ExecutablesAsyncSpecs.cs @@ -0,0 +1,175 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; +using Xunit; + +namespace Polly.Specs.Executables +{ + public class ExecutablesAsyncSpecs + { + [Fact] + public async Task Should_execute_user_delegate_with_input_parameter() + { + var policy = Policy.NoOpAsync(); + + Int16 input1 = 1; + Int64 captured = 0; + + await policy.ExecuteAsync((context, token, captureContext, input) => + { + captured = input; + return Task.CompletedTask; + }, new Context(), + CancellationToken.None, + continueOnCapturedContext: false, + input1); + + captured.Should().Be(input1); + } + + [Fact] + public async Task Should_execute_user_delegate_with_two_input_parameters() + { + var policy = Policy.NoOpAsync(); + + Int16 input1 = 1; + Int32 input2 = 2; + Int64 captured = 0; + + await policy.ExecuteAsync((context, token, captureContext, t1, t2) => + { + captured = t1 + t2; + return Task.CompletedTask; + }, new Context(), + CancellationToken.None, + continueOnCapturedContext: false, + input1, + input2); + + captured.Should().Be(input1 + input2); + } + + [Fact] + public async Task Should_execute_user_delegate_with_input_parameter_and_return_type() + { + var policy = Policy.NoOpAsync(); + + Int16 input1 = 1; + Int64 captured = await policy.ExecuteAsync(async (context, token, captureContext, input) => + { + await Task.CompletedTask; + return input; + }, new Context(), + CancellationToken.None, + continueOnCapturedContext: false, + input1); + + captured.Should().Be(input1); + } + + [Fact] + public async Task Should_execute_user_delegate_with_two_input_parameters_and_return_type() + { + var policy = Policy.NoOpAsync(); + + Int16 input1 = 1; + Int32 input2 = 2; + Int64 captured = await policy.ExecuteAsync(async (context, token, captureContext, t1, t2) => + { + await Task.CompletedTask; + return t1 + t2; + }, new Context(), + CancellationToken.None, + continueOnCapturedContext: false, + input1, + input2); + + captured.Should().Be(input1 + input2); + } + + [Fact] + public async Task Should_executeandcapture_user_delegate_with_input_parameter() + { + var policy = Policy.NoOpAsync(); + + Int16 input1 = 1; + Int64 captured = 0; + + var policyResult = await policy.ExecuteAndCaptureAsync((context, token, captureContext, input) => + { + captured = input; + return Task.CompletedTask; + }, new Context(), + CancellationToken.None, + continueOnCapturedContext: false, + input1); + + policyResult.Outcome.Should().Be(OutcomeType.Successful); + captured.Should().Be(input1); + } + + [Fact] + public async Task Should_executeandcapture_user_delegate_with_two_input_parameters() + { + var policy = Policy.NoOpAsync(); + + Int16 input1 = 1; + Int32 input2 = 2; + Int64 captured = 0; + + var policyResult = await policy.ExecuteAndCaptureAsync((context, token, captureContext, t1, t2) => + { + captured = t1 + t2; + return Task.CompletedTask; + }, new Context(), + CancellationToken.None, + continueOnCapturedContext: false, + input1, + input2); + + policyResult.Outcome.Should().Be(OutcomeType.Successful); + captured.Should().Be(input1 + input2); + } + + [Fact] + public async Task Should_executeandcapture_user_delegate_with_input_parameter_and_return_type() + { + var policy = Policy.NoOpAsync(); + + Int16 input1 = 1; + var policyResult = await policy.ExecuteAndCaptureAsync(async (context, token, captureContext, input) => + { + await Task.CompletedTask; + return input; + }, new Context(), + CancellationToken.None, + continueOnCapturedContext: false, + input1); + + policyResult.Outcome.Should().Be(OutcomeType.Successful); + policyResult.Result.Should().Be(input1); + } + + [Fact] + public async Task Should_executeandcapture_user_delegate_with_two_input_parameters_and_return_type() + { + var policy = Policy.NoOpAsync(); + + Int16 input1 = 1; + Int32 input2 = 2; + var policyResult = await policy.ExecuteAndCaptureAsync(async (context, token, captureContext, t1, t2) => + { + await Task.CompletedTask; + return t1 + t2; + }, new Context(), + CancellationToken.None, + continueOnCapturedContext: false, + input1, + input2); + + policyResult.Outcome.Should().Be(OutcomeType.Successful); + policyResult.Result.Should().Be(input1 + input2); + } + } +} diff --git a/src/Polly.Specs/Executables/ExecutablesSyncSpecs.cs b/src/Polly.Specs/Executables/ExecutablesSyncSpecs.cs new file mode 100644 index 00000000000..0eef6a559ee --- /dev/null +++ b/src/Polly.Specs/Executables/ExecutablesSyncSpecs.cs @@ -0,0 +1,146 @@ +using System; +using System.Threading; +using FluentAssertions; +using Xunit; + +namespace Polly.Specs.Executables +{ + public class ExecutablesSyncSpecs + { + [Fact] + public void Should_execute_user_delegate_with_input_parameter() + { + var policy = Policy.NoOp(); + + Int16 input1 = 1; + Int64 captured = 0; + + policy.Execute((context, token, input) => + { + captured = input; + }, new Context(), + CancellationToken.None, + input1); + + captured.Should().Be(input1); + } + + [Fact] + public void Should_execute_user_delegate_with_two_input_parameters() + { + var policy = Policy.NoOp(); + + Int16 input1 = 1; + Int32 input2 = 2; + Int64 captured = 0; + + policy.Execute((context, token, t1, t2) => + { + captured = t1 + t2; + }, new Context(), + CancellationToken.None, + input1, + input2); + + captured.Should().Be(input1 + input2); + } + + [Fact] + public void Should_execute_user_delegate_with_input_parameter_and_return_type() + { + var policy = Policy.NoOp(); + + Int16 input1 = 1; + double captured = policy.Execute((context, token, input) => input, new Context(), + CancellationToken.None, + input1); + + captured.Should().Be(input1); + } + + [Fact] + public void Should_execute_user_delegate_with_two_input_parameters_and_return_type() + { + var policy = Policy.NoOp(); + + Int16 input1 = 1; + Int32 input2 = 2; + double captured = policy.Execute((context, token, t1, t2) => t1 + t2, new Context(), + CancellationToken.None, + input1, + input2); + + captured.Should().Be(input1 + input2); + } + + [Fact] + public void Should_executeandcapture_user_delegate_with_input_parameter() + { + var policy = Policy.NoOp(); + + Int16 input1 = 1; + double captured = 0; + + var policyResult = policy.ExecuteAndCapture((context, token, input) => + { + captured = input; + }, new Context(), + CancellationToken.None, + input1); + + policyResult.Outcome.Should().Be(OutcomeType.Successful); + captured.Should().Be(input1); + } + + [Fact] + public void Should_executeandcapture_user_delegate_with_two_input_parameters() + { + var policy = Policy.NoOp(); + + Int16 input1 = 1; + Int32 input2 = 2; + double captured = 0; + + var policyResult = policy.ExecuteAndCapture((context, token, t1, t2) => + { + captured = t1 + t2; + }, new Context(), + CancellationToken.None, + input1, + input2); + + policyResult.Outcome.Should().Be(OutcomeType.Successful); + captured.Should().Be(input1 + input2); + } + + [Fact] + public void Should_executeandcapture_user_delegate_with_input_parameter_and_return_type() + { + var policy = Policy.NoOp(); + + Int16 input1 = 1; + var policyResult = policy.ExecuteAndCapture((context, token, input) => input, new Context(), + CancellationToken.None, + input1); + + policyResult.Outcome.Should().Be(OutcomeType.Successful); + policyResult.Result.Should().Be(input1); + } + + [Fact] + public void Should_executeandcapture_user_delegate_with_two_input_parameters_and_return_type() + { + var policy = Policy.NoOp(); + + Int16 input1 = 1; + Int32 input2 = 2; + var policyResult = policy.ExecuteAndCapture((context, token, t1, t2) => t1 + t2, new Context(), + CancellationToken.None, + input1, + input2); + + policyResult.Outcome.Should().Be(OutcomeType.Successful); + policyResult.Result.Should().Be(input1 + input2); + } + } +} diff --git a/src/Polly.Specs/Executables/ExecutablesTResultAsyncSpecs.cs b/src/Polly.Specs/Executables/ExecutablesTResultAsyncSpecs.cs new file mode 100644 index 00000000000..d722cee1bdb --- /dev/null +++ b/src/Polly.Specs/Executables/ExecutablesTResultAsyncSpecs.cs @@ -0,0 +1,90 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; +using Xunit; + +namespace Polly.Specs.Executables +{ + public class ExecutablesTResultAsyncSpecs + { + + [Fact] + public async Task Should_execute_user_delegate_with_input_parameter_and_return_type() + { + var policy = Policy.NoOpAsync(); + + Int16 input1 = 1; + Int64 captured = await policy.ExecuteAsync(async (context, token, captureContext, input) => + { + await Task.CompletedTask; + return input; + }, new Context(), + CancellationToken.None, + continueOnCapturedContext: false, + input1); + + captured.Should().Be(input1); + } + + [Fact] + public async Task Should_execute_user_delegate_with_two_input_parameters_and_return_type() + { + var policy = Policy.NoOpAsync(); + + Int16 input1 = 1; + Int32 input2 = 2; + Int64 captured = await policy.ExecuteAsync(async (context, token, captureContext, t1, t2) => + { + await Task.CompletedTask; + return t1 + t2; + }, new Context(), + CancellationToken.None, + continueOnCapturedContext: false, + input1, + input2); + + captured.Should().Be(input1 + input2); + } + + [Fact] + public async Task Should_executeandcapture_user_delegate_with_input_parameter_and_return_type() + { + var policy = Policy.NoOpAsync(); + + Int16 input1 = 1; + var policyResult = await policy.ExecuteAndCaptureAsync(async (context, token, captureContext, input) => + { + await Task.CompletedTask; + return input; + }, new Context(), + CancellationToken.None, + continueOnCapturedContext: false, + input1); + + policyResult.Outcome.Should().Be(OutcomeType.Successful); + policyResult.Result.Should().Be(input1); + } + + [Fact] + public async Task Should_executeandcapture_user_delegate_with_two_input_parameters_and_return_type() + { + var policy = Policy.NoOpAsync(); + + Int16 input1 = 1; + Int32 input2 = 2; + var policyResult = await policy.ExecuteAndCaptureAsync(async (context, token, captureContext, t1, t2) => + { + await Task.CompletedTask; + return t1 + t2; + }, new Context(), + CancellationToken.None, + continueOnCapturedContext: false, + input1, + input2); + + policyResult.Outcome.Should().Be(OutcomeType.Successful); + policyResult.Result.Should().Be(input1 + input2); + } + } +} diff --git a/src/Polly.Specs/Executables/ExecutablesTResultSyncSpecs.cs b/src/Polly.Specs/Executables/ExecutablesTResultSyncSpecs.cs new file mode 100644 index 00000000000..1a5b298c8f8 --- /dev/null +++ b/src/Polly.Specs/Executables/ExecutablesTResultSyncSpecs.cs @@ -0,0 +1,68 @@ +using System; +using System.Threading; +using FluentAssertions; +using Xunit; + +namespace Polly.Specs.Executables +{ + public class ExecutablesTResultSyncSpecs + { + [Fact] + public void Should_execute_user_delegate_with_input_parameter_and_return_type() + { + var policy = Policy.NoOp(); + + Int16 input1 = 1; + Int64 captured = policy.Execute((context, token, input) => input, new Context(), + CancellationToken.None, + input1); + + captured.Should().Be(input1); + } + + [Fact] + public void Should_execute_user_delegate_with_two_input_parameters_and_return_type() + { + var policy = Policy.NoOp(); + + Int16 input1 = 1; + Int32 input2 = 2; + Int64 captured = policy.Execute((context, token, t1, t2) => t1 + t2, new Context(), + CancellationToken.None, + input1, + input2); + + captured.Should().Be(input1 + input2); + } + + [Fact] + public void Should_executeandcapture_user_delegate_with_input_parameter_and_return_type() + { + var policy = Policy.NoOp(); + + Int16 input1 = 1; + var policyResult = policy.ExecuteAndCapture((context, token, input) => input, new Context(), + CancellationToken.None, + input1); + + policyResult.Outcome.Should().Be(OutcomeType.Successful); + policyResult.Result.Should().Be(input1); + } + + [Fact] + public void Should_executeandcapture_user_delegate_with_two_input_parameters_and_return_type() + { + var policy = Policy.NoOp(); + + Int16 input1 = 1; + Int32 input2 = 2; + var policyResult = policy.ExecuteAndCapture((context, token, t1, t2) => t1 + t2, new Context(), + CancellationToken.None, + input1, + input2); + + policyResult.Outcome.Should().Be(OutcomeType.Successful); + policyResult.Result.Should().Be(input1 + input2); + } + } +} diff --git a/src/Polly.Specs/Fallback/FallbackAsyncSpecs.cs b/src/Polly.Specs/Fallback/FallbackAsyncSpecs.cs index 8c6cbe8c311..ad8f6f1b2ea 100644 --- a/src/Polly.Specs/Fallback/FallbackAsyncSpecs.cs +++ b/src/Polly.Specs/Fallback/FallbackAsyncSpecs.cs @@ -4,7 +4,6 @@ using System.Threading.Tasks; using FluentAssertions; using Polly.Specs.Helpers; -using Polly.Utilities; using Xunit; using Scenario = Polly.Specs.Helpers.IAsyncPolicyExtensions.ExceptionAndOrCancellationScenario; diff --git a/src/Polly.Specs/Fallback/FallbackTResultAsyncSpecs.cs b/src/Polly.Specs/Fallback/FallbackTResultAsyncSpecs.cs index 0dcce5916f3..a68a71d5b0d 100644 --- a/src/Polly.Specs/Fallback/FallbackTResultAsyncSpecs.cs +++ b/src/Polly.Specs/Fallback/FallbackTResultAsyncSpecs.cs @@ -4,7 +4,6 @@ using System.Threading.Tasks; using FluentAssertions; using Polly.Specs.Helpers; -using Polly.Utilities; using Xunit; using Scenario = Polly.Specs.Helpers.IAsyncPolicyTResultExtensions.ResultAndOrCancellationScenario; @@ -506,7 +505,7 @@ public async Task Context_should_be_empty_at_fallbackAction_if_execute_not_calle [Fact] public async Task Should_call_fallbackAction_with_the_fault() { - DelegateResult fallbackOutcome = null; + DelegateResult? fallbackOutcome = null; Func, Context, CancellationToken, Task> fallbackAction = (outcome, ctx, ct) => { fallbackOutcome = outcome; return Task.FromResult(ResultPrimitive.Substitute); }; @@ -521,14 +520,14 @@ public async Task Should_call_fallbackAction_with_the_fault() result.Should().Be(ResultPrimitive.Substitute); fallbackOutcome.Should().NotBeNull(); - fallbackOutcome.Exception.Should().BeNull(); - fallbackOutcome.Result.Should().Be(ResultPrimitive.Fault); + fallbackOutcome.Value.Exception.Should().BeNull(); + fallbackOutcome.Value.Result.Should().Be(ResultPrimitive.Fault); } [Fact] public async Task Should_call_fallbackAction_with_the_fault_when_execute_and_capture() { - DelegateResult fallbackOutcome = null; + DelegateResult? fallbackOutcome = null; Func, Context, CancellationToken, Task> fallbackAction = (outcome, ctx, ct) => { fallbackOutcome = outcome; return Task.FromResult(ResultPrimitive.Substitute); }; @@ -544,14 +543,14 @@ public async Task Should_call_fallbackAction_with_the_fault_when_execute_and_cap result.Result.Should().Be(ResultPrimitive.Substitute); fallbackOutcome.Should().NotBeNull(); - fallbackOutcome.Exception.Should().BeNull(); - fallbackOutcome.Result.Should().Be(ResultPrimitive.Fault); + fallbackOutcome.Value.Exception.Should().BeNull(); + fallbackOutcome.Value.Result.Should().Be(ResultPrimitive.Fault); } [Fact] public async Task Should_not_call_fallbackAction_with_the_fault_if_fault_unhandled() { - DelegateResult fallbackOutcome = null; + DelegateResult? fallbackOutcome = null; Func, Context, CancellationToken, Task> fallbackAction = (outcome, ctx, ct) => { fallbackOutcome = outcome; return Task.FromResult(ResultPrimitive.Substitute); }; diff --git a/src/Polly.Specs/Fallback/FallbackTResultSpecs.cs b/src/Polly.Specs/Fallback/FallbackTResultSpecs.cs index 7fb4cf7ca18..c4765008231 100644 --- a/src/Polly.Specs/Fallback/FallbackTResultSpecs.cs +++ b/src/Polly.Specs/Fallback/FallbackTResultSpecs.cs @@ -529,7 +529,7 @@ public void Context_should_be_empty_at_fallbackAction_if_execute_not_called_with [Fact] public void Should_call_fallbackAction_with_the_fault() { - DelegateResult fallbackOutcome = null; + DelegateResult? fallbackOutcome = null; Func, Context, CancellationToken, ResultPrimitive> fallbackAction = (outcome, ctx, ct) => { fallbackOutcome = outcome; return ResultPrimitive.Substitute; }; @@ -544,14 +544,14 @@ public void Should_call_fallbackAction_with_the_fault() .Should().Be(ResultPrimitive.Substitute); fallbackOutcome.Should().NotBeNull(); - fallbackOutcome.Exception.Should().BeNull(); - fallbackOutcome.Result.Should().Be(ResultPrimitive.Fault); + fallbackOutcome.Value.Exception.Should().BeNull(); + fallbackOutcome.Value.Result.Should().Be(ResultPrimitive.Fault); } [Fact] public void Should_call_fallbackAction_with_the_fault_when_execute_and_capture() { - DelegateResult fallbackOutcome = null; + DelegateResult? fallbackOutcome = null; Func, Context, CancellationToken, ResultPrimitive> fallbackAction = (outcome, ctx, ct) => { fallbackOutcome = outcome; return ResultPrimitive.Substitute; }; @@ -567,14 +567,14 @@ public void Should_call_fallbackAction_with_the_fault_when_execute_and_capture() result.Result.Should().Be(ResultPrimitive.Substitute); fallbackOutcome.Should().NotBeNull(); - fallbackOutcome.Exception.Should().BeNull(); - fallbackOutcome.Result.Should().Be(ResultPrimitive.Fault); + fallbackOutcome.Value.Exception.Should().BeNull(); + fallbackOutcome.Value.Result.Should().Be(ResultPrimitive.Fault); } [Fact] public void Should_not_call_fallbackAction_with_the_fault_if_fault_unhandled() { - DelegateResult fallbackOutcome = null; + DelegateResult? fallbackOutcome = null; Func, Context, CancellationToken, ResultPrimitive> fallbackAction = (outcome, ctx, ct) => { fallbackOutcome = outcome; return ResultPrimitive.Substitute; }; diff --git a/src/Polly.Specs/Helpers/Caching/StubErroringCacheProvider.cs b/src/Polly.Specs/Helpers/Caching/StubErroringCacheProvider.cs index 24da3019c21..ebb4ffe17ca 100644 --- a/src/Polly.Specs/Helpers/Caching/StubErroringCacheProvider.cs +++ b/src/Polly.Specs/Helpers/Caching/StubErroringCacheProvider.cs @@ -2,7 +2,6 @@ using System.Threading; using System.Threading.Tasks; using Polly.Caching; -using Polly.Utilities; namespace Polly.Specs.Helpers.Caching { diff --git a/src/Polly.Specs/Helpers/Custom/AddBehaviourIfHandle/AddBehaviourIfHandleEngine.cs b/src/Polly.Specs/Helpers/Custom/AddBehaviourIfHandle/AddBehaviourIfHandleEngine.cs index 464ca555a40..caf530c2b2d 100644 --- a/src/Polly.Specs/Helpers/Custom/AddBehaviourIfHandle/AddBehaviourIfHandleEngine.cs +++ b/src/Polly.Specs/Helpers/Custom/AddBehaviourIfHandle/AddBehaviourIfHandleEngine.cs @@ -6,17 +6,18 @@ namespace Polly.Specs.Helpers.Custom.AddBehaviourIfHandle { internal static class AddBehaviourIfHandleEngine { - internal static TResult Implementation( + internal static TResult Implementation( + in TExecutable action, + Context context, + CancellationToken cancellationToken, ExceptionPredicates shouldHandleExceptionPredicates, ResultPredicates shouldHandleResultPredicates, - Action> behaviourIfHandle, - Func action, - Context context, - CancellationToken cancellationToken) + Action> behaviourIfHandle) + where TExecutable : ISyncExecutable { try { - TResult result = action(context, cancellationToken); + TResult result = action.Execute(context, cancellationToken); if (shouldHandleResultPredicates.AnyMatch(result)) { diff --git a/src/Polly.Specs/Helpers/Custom/AddBehaviourIfHandle/AddBehaviourIfHandlePolicy.cs b/src/Polly.Specs/Helpers/Custom/AddBehaviourIfHandle/AddBehaviourIfHandlePolicy.cs index 71b5709b49a..40e7fbf4434 100644 --- a/src/Polly.Specs/Helpers/Custom/AddBehaviourIfHandle/AddBehaviourIfHandlePolicy.cs +++ b/src/Polly.Specs/Helpers/Custom/AddBehaviourIfHandle/AddBehaviourIfHandlePolicy.cs @@ -13,18 +13,16 @@ internal AddBehaviourIfHandlePolicy(Action behaviourIfHandle, PolicyB _behaviourIfHandle = behaviourIfHandle ?? throw new ArgumentNullException(nameof(behaviourIfHandle)); } - protected override TResult Implementation( - Func action, - Context context, + protected override TResult SyncGenericImplementation(in TExecutable action, Context context, CancellationToken cancellationToken) { - return AddBehaviourIfHandleEngine.Implementation( - ExceptionPredicates, - ResultPredicates.None, - outcome => _behaviourIfHandle(outcome.Exception), + return AddBehaviourIfHandleEngine.Implementation( action, context, - cancellationToken + cancellationToken, + ExceptionPredicates, + ResultPredicates.None, + outcome => _behaviourIfHandle(outcome.Exception) ); } } @@ -41,15 +39,15 @@ internal AddBehaviourIfHandlePolicy( _behaviourIfHandle = behaviourIfHandle ?? throw new ArgumentNullException(nameof(behaviourIfHandle)); } - protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken) + protected override TResult SyncGenericImplementation(in TExecutable action, Context context, CancellationToken cancellationToken) { return AddBehaviourIfHandleEngine.Implementation( - ExceptionPredicates, - ResultPredicates, - _behaviourIfHandle, action, context, - cancellationToken + cancellationToken, + ExceptionPredicates, + ResultPredicates, + _behaviourIfHandle ); } } diff --git a/src/Polly.Specs/Helpers/Custom/AddBehaviourIfHandle/AsyncAddBehaviourIfHandleEngine.cs b/src/Polly.Specs/Helpers/Custom/AddBehaviourIfHandle/AsyncAddBehaviourIfHandleEngine.cs index 40801dec03f..1f01e0a47f5 100644 --- a/src/Polly.Specs/Helpers/Custom/AddBehaviourIfHandle/AsyncAddBehaviourIfHandleEngine.cs +++ b/src/Polly.Specs/Helpers/Custom/AddBehaviourIfHandle/AsyncAddBehaviourIfHandleEngine.cs @@ -7,18 +7,20 @@ namespace Polly.Specs.Helpers.Custom.AddBehaviourIfHandle { internal static class AsyncAddBehaviourIfHandleEngine { - internal static async Task ImplementationAsync( - ExceptionPredicates shouldHandleExceptionPredicates, - ResultPredicates shouldHandleResultPredicates, - Func, Task> behaviourIfHandle, - Func> action, + internal static async Task ImplementationAsync( + TExecutableAsync action, Context context, CancellationToken cancellationToken, - bool continueOnCapturedContext) + bool continueOnCapturedContext, + ExceptionPredicates shouldHandleExceptionPredicates, + ResultPredicates shouldHandleResultPredicates, + Func, Task> behaviourIfHandle + ) + where TExecutableAsync : IAsyncExecutable { try { - TResult result = await action(context, cancellationToken).ConfigureAwait(continueOnCapturedContext); + TResult result = await action.ExecuteAsync(context, cancellationToken, continueOnCapturedContext).ConfigureAwait(continueOnCapturedContext); if (shouldHandleResultPredicates.AnyMatch(result)) { diff --git a/src/Polly.Specs/Helpers/Custom/AddBehaviourIfHandle/AsyncAddBehaviourIfHandlePolicy.cs b/src/Polly.Specs/Helpers/Custom/AddBehaviourIfHandle/AsyncAddBehaviourIfHandlePolicy.cs index c5489d34cf1..5c243229937 100644 --- a/src/Polly.Specs/Helpers/Custom/AddBehaviourIfHandle/AsyncAddBehaviourIfHandlePolicy.cs +++ b/src/Polly.Specs/Helpers/Custom/AddBehaviourIfHandle/AsyncAddBehaviourIfHandlePolicy.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using System.Threading.Tasks; namespace Polly.Specs.Helpers.Custom.AddBehaviourIfHandle @@ -15,17 +16,17 @@ internal AsyncAddBehaviourIfHandlePolicy( _behaviourIfHandle = behaviourIfHandle ?? throw new ArgumentNullException(nameof(behaviourIfHandle)); } - protected override Task ImplementationAsync(Func> action, Context context, System.Threading.CancellationToken cancellationToken, - bool continueOnCapturedContext) + protected override Task AsyncGenericImplementation(TExecutableAsync action, Context context, + CancellationToken cancellationToken, bool continueOnCapturedContext) { return AsyncAddBehaviourIfHandleEngine.ImplementationAsync( - ExceptionPredicates, - ResultPredicates.None, - outcome => _behaviourIfHandle(outcome.Exception), action, context, cancellationToken, - continueOnCapturedContext + continueOnCapturedContext, + ExceptionPredicates, + ResultPredicates.None, + outcome => _behaviourIfHandle(outcome.Exception) ); } } @@ -43,18 +44,17 @@ internal AsyncAddBehaviourIfHandlePolicy( } - protected override Task ImplementationAsync(Func> action, Context context, System.Threading.CancellationToken cancellationToken, - bool continueOnCapturedContext) + protected override Task AsyncGenericImplementation(TExecutableAsync action, Context context, + CancellationToken cancellationToken, bool continueOnCapturedContext) { return AsyncAddBehaviourIfHandleEngine.ImplementationAsync( - ExceptionPredicates, - ResultPredicates, - _behaviourIfHandle, action, context, cancellationToken, - continueOnCapturedContext - ); + continueOnCapturedContext, + ExceptionPredicates, + ResultPredicates, + _behaviourIfHandle); } } } diff --git a/src/Polly.Specs/Helpers/Custom/PreExecute/AsyncPreExecuteEngine.cs b/src/Polly.Specs/Helpers/Custom/PreExecute/AsyncPreExecuteEngine.cs index 4f41915a540..12c6f52d3a7 100644 --- a/src/Polly.Specs/Helpers/Custom/PreExecute/AsyncPreExecuteEngine.cs +++ b/src/Polly.Specs/Helpers/Custom/PreExecute/AsyncPreExecuteEngine.cs @@ -6,28 +6,17 @@ namespace Polly.Specs.Helpers.Custom.PreExecute { internal static class AsyncPreExecuteEngine { - internal static async Task ImplementationAsync( - Func preExecute, - Func action, + internal static async Task ImplementationAsync( + TExecutableAsync action, Context context, CancellationToken cancellationToken, - bool continueOnCapturedContext) + bool continueOnCapturedContext, + Func preExecute) + where TExecutableAsync : IAsyncExecutable { await (preExecute?.Invoke() ?? Task.CompletedTask).ConfigureAwait(continueOnCapturedContext); - await action(context, cancellationToken).ConfigureAwait(continueOnCapturedContext); - } - - internal static async Task ImplementationAsync( - Func preExecute, - Func> action, - Context context, - CancellationToken cancellationToken, - bool continueOnCapturedContext) - { - await (preExecute?.Invoke() ?? Task.CompletedTask).ConfigureAwait(continueOnCapturedContext); - - return await action(context, cancellationToken).ConfigureAwait(continueOnCapturedContext); + return await action.ExecuteAsync(context, cancellationToken, continueOnCapturedContext).ConfigureAwait(continueOnCapturedContext); } } } \ No newline at end of file diff --git a/src/Polly.Specs/Helpers/Custom/PreExecute/AsyncPreExecutePolicy.cs b/src/Polly.Specs/Helpers/Custom/PreExecute/AsyncPreExecutePolicy.cs index 15e49b2c35d..89a24f39867 100644 --- a/src/Polly.Specs/Helpers/Custom/PreExecute/AsyncPreExecutePolicy.cs +++ b/src/Polly.Specs/Helpers/Custom/PreExecute/AsyncPreExecutePolicy.cs @@ -18,10 +18,10 @@ internal AsyncPreExecutePolicy(Func preExecute) _preExecute = preExecute ?? throw new ArgumentNullException(nameof(preExecute)); } - protected override Task ImplementationAsync(Func> action, Context context, CancellationToken cancellationToken, - bool continueOnCapturedContext) + protected override Task AsyncGenericImplementation(TExecutableAsync action, Context context, + CancellationToken cancellationToken, bool continueOnCapturedContext) { - return AsyncPreExecuteEngine.ImplementationAsync(_preExecute, action, context, cancellationToken, continueOnCapturedContext); + return AsyncPreExecuteEngine.ImplementationAsync(action, context, cancellationToken, continueOnCapturedContext, _preExecute); } } @@ -39,10 +39,10 @@ internal AsyncPreExecutePolicy(Func preExecute) _preExecute = preExecute ?? throw new ArgumentNullException(nameof(preExecute)); } - protected override Task ImplementationAsync(Func> action, Context context, CancellationToken cancellationToken, - bool continueOnCapturedContext) + protected override Task AsyncGenericImplementation(TExecutableAsync action, Context context, + CancellationToken cancellationToken, bool continueOnCapturedContext) { - return AsyncPreExecuteEngine.ImplementationAsync(_preExecute, action, context, cancellationToken, continueOnCapturedContext); + return AsyncPreExecuteEngine.ImplementationAsync(action, context, cancellationToken, continueOnCapturedContext, _preExecute); } } } \ No newline at end of file diff --git a/src/Polly.Specs/Helpers/Custom/PreExecute/PreExecuteEngine.cs b/src/Polly.Specs/Helpers/Custom/PreExecute/PreExecuteEngine.cs index 9a4a787d877..97eed2d6706 100644 --- a/src/Polly.Specs/Helpers/Custom/PreExecute/PreExecuteEngine.cs +++ b/src/Polly.Specs/Helpers/Custom/PreExecute/PreExecuteEngine.cs @@ -5,26 +5,16 @@ namespace Polly.Specs.Helpers.Custom.PreExecute { internal static class PreExecuteEngine { - internal static void Implementation( - Action preExecute, - Action action, - Context context, - CancellationToken cancellationToken) - { - preExecute?.Invoke(); - - action(context, cancellationToken); - } - - internal static TResult Implementation( - Action preExecute, - Func action, + internal static TResult Implementation( + in TExecutable action, Context context, - CancellationToken cancellationToken) + CancellationToken cancellationToken, + Action preExecute) + where TExecutable : ISyncExecutable { preExecute?.Invoke(); - return action(context, cancellationToken); + return action.Execute(context, cancellationToken); } } } \ No newline at end of file diff --git a/src/Polly.Specs/Helpers/Custom/PreExecute/PreExecutePolicy.cs b/src/Polly.Specs/Helpers/Custom/PreExecute/PreExecutePolicy.cs index d41d9c3719c..d05c1f4fbab 100644 --- a/src/Polly.Specs/Helpers/Custom/PreExecute/PreExecutePolicy.cs +++ b/src/Polly.Specs/Helpers/Custom/PreExecute/PreExecutePolicy.cs @@ -17,9 +17,10 @@ internal PreExecutePolicy(Action preExecute) _preExecute = preExecute ?? throw new ArgumentNullException(nameof(preExecute)); } - protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken) + protected override TResult SyncGenericImplementation(in TExecutable action, Context context, + CancellationToken cancellationToken) { - return PreExecuteEngine.Implementation(_preExecute, action, context, cancellationToken); + return PreExecuteEngine.Implementation(action, context, cancellationToken, _preExecute); } } @@ -37,9 +38,9 @@ internal PreExecutePolicy(Action preExecute) _preExecute = preExecute ?? throw new ArgumentNullException(nameof(preExecute)); } - protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken) + protected override TResult SyncGenericImplementation(in TExecutable action, Context context, CancellationToken cancellationToken) { - return PreExecuteEngine.Implementation(_preExecute, action, context, cancellationToken); + return PreExecuteEngine.Implementation(action, context, cancellationToken, _preExecute); } } } \ No newline at end of file diff --git a/src/Polly.Specs/Helpers/IAsyncPolicyExtensions.cs b/src/Polly.Specs/Helpers/IAsyncPolicyExtensions.cs index d51671e897a..ca1bd55dcef 100644 --- a/src/Polly.Specs/Helpers/IAsyncPolicyExtensions.cs +++ b/src/Polly.Specs/Helpers/IAsyncPolicyExtensions.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Polly.Utilities; namespace Polly.Specs.Helpers { diff --git a/src/Polly/Utilities/TaskHelper.cs b/src/Polly.Specs/Helpers/TaskHelper.cs similarity index 56% rename from src/Polly/Utilities/TaskHelper.cs rename to src/Polly.Specs/Helpers/TaskHelper.cs index 4264d9ebaff..867e4bb5bbc 100644 --- a/src/Polly/Utilities/TaskHelper.cs +++ b/src/Polly.Specs/Helpers/TaskHelper.cs @@ -1,6 +1,6 @@ using System.Threading.Tasks; -namespace Polly.Utilities +namespace Polly.Specs.Helpers { /// /// Task helpers. @@ -10,6 +10,6 @@ public static class TaskHelper /// /// Defines a completed Task for use as a completed, empty asynchronous delegate. /// - public static Task EmptyTask = Task.FromResult(true); + public static readonly Task EmptyTask = Task.CompletedTask; // This should now be inlined, given all targets support it. To do in its own PR, to avoid creating noise in other PRs. } } diff --git a/src/Polly.Specs/NoOp/NoOpAsyncSpecs.cs b/src/Polly.Specs/NoOp/NoOpAsyncSpecs.cs index 089b429b56b..140bbd0cb05 100644 --- a/src/Polly.Specs/NoOp/NoOpAsyncSpecs.cs +++ b/src/Polly.Specs/NoOp/NoOpAsyncSpecs.cs @@ -1,6 +1,6 @@ using System.Threading; using FluentAssertions; -using Polly.Utilities; +using Polly.Specs.Helpers; using Xunit; namespace Polly.Specs.NoOp diff --git a/src/Polly.Specs/PolicyAsyncSpecs.cs b/src/Polly.Specs/PolicyAsyncSpecs.cs index cea4ca852b8..238a39ca3f2 100644 --- a/src/Polly.Specs/PolicyAsyncSpecs.cs +++ b/src/Polly.Specs/PolicyAsyncSpecs.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using FluentAssertions; -using Polly.Utilities; +using Polly.Specs.Helpers; using Xunit; namespace Polly.Specs diff --git a/src/Polly.Specs/PolicyContextAndKeyAsyncSpecs.cs b/src/Polly.Specs/PolicyContextAndKeyAsyncSpecs.cs index fd75232f419..087662bcec3 100644 --- a/src/Polly.Specs/PolicyContextAndKeyAsyncSpecs.cs +++ b/src/Polly.Specs/PolicyContextAndKeyAsyncSpecs.cs @@ -2,7 +2,6 @@ using System.Threading.Tasks; using FluentAssertions; using Polly.Specs.Helpers; -using Polly.Utilities; using Xunit; namespace Polly.Specs @@ -16,7 +15,7 @@ public void Should_be_able_fluently_to_configure_the_policy_key() { var policy = Policy.Handle().RetryAsync().WithPolicyKey(Guid.NewGuid().ToString()); - policy.Should().BeAssignableTo(); + policy.Should().BeAssignableTo(); } [Fact] @@ -199,7 +198,7 @@ public void Should_be_able_fluently_to_configure_the_policy_key() { var policy = Policy.HandleResult(0).RetryAsync().WithPolicyKey(Guid.NewGuid().ToString()); - policy.Should().BeAssignableTo>(); + policy.Should().BeAssignableTo>(); } [Fact] diff --git a/src/Polly.Specs/PolicyContextAndKeySpecs.cs b/src/Polly.Specs/PolicyContextAndKeySpecs.cs index 931e5c7a71a..badf7d11a15 100644 --- a/src/Polly.Specs/PolicyContextAndKeySpecs.cs +++ b/src/Polly.Specs/PolicyContextAndKeySpecs.cs @@ -14,7 +14,7 @@ public void Should_be_able_fluently_to_configure_the_policy_key() { var policy = Policy.Handle().Retry().WithPolicyKey(Guid.NewGuid().ToString()); - policy.Should().BeAssignableTo(); + policy.Should().BeAssignableTo(); } [Fact] @@ -195,7 +195,7 @@ public void Should_be_able_fluently_to_configure_the_policy_key() { var policy = Policy.HandleResult(0).Retry().WithPolicyKey(Guid.NewGuid().ToString()); - policy.Should().BeAssignableTo>(); + policy.Should().BeAssignableTo>(); } [Fact] diff --git a/src/Polly.Specs/Registry/PolicyRegistrySpecs.cs b/src/Polly.Specs/Registry/PolicyRegistrySpecs.cs index 62a4748d977..a9285a2fd0a 100644 --- a/src/Polly.Specs/Registry/PolicyRegistrySpecs.cs +++ b/src/Polly.Specs/Registry/PolicyRegistrySpecs.cs @@ -12,7 +12,7 @@ namespace Polly.Specs.Registry { public class PolicyRegistrySpecs { - IPolicyRegistry _registry; + readonly IPolicyRegistry _registry; public PolicyRegistrySpecs() { @@ -128,7 +128,7 @@ public void Should_be_able_to_overwrite_existing_Policy_if_key_exists_when_inser _registry.Count.Should().Be(1); - _registry.Get(key).Should().BeSameAs(policy_new); + _registry.Get(key).Should().BeSameAs(policy_new); } [Fact] @@ -143,7 +143,7 @@ public void Should_be_able_to_overwrite_existing_PolicyTResult_if_key_exists_whe _registry.Count.Should().Be(1); - _registry.Get>(key).Should().BeSameAs(policy_new); + _registry.Get>(key).Should().BeSameAs(policy_new); } [Fact] @@ -173,10 +173,9 @@ public void Should_be_able_to_retrieve_stored_Policy_using_TryGet() { ISyncPolicy policy = Policy.NoOp(); string key = Guid.NewGuid().ToString(); - ISyncPolicy outPolicy = null; _registry.Add(key, policy); - _registry.TryGet(key, out outPolicy).Should().BeTrue(); + _registry.TryGet(key, out ISyncPolicy outPolicy).Should().BeTrue(); outPolicy.Should().BeSameAs(policy); } @@ -185,10 +184,9 @@ public void Should_be_able_to_retrieve_stored_PolicyTResult_using_TryGet() { ISyncPolicy policy = Policy.HandleResult(ResultPrimitive.Fault).Retry(); string key = Guid.NewGuid().ToString(); - ISyncPolicy outPolicy = null; _registry.Add(key, policy); - _registry.TryGet(key, out outPolicy).Should().BeTrue(); + _registry.TryGet(key, out ISyncPolicy outPolicy).Should().BeTrue(); outPolicy.Should().BeSameAs(policy); } @@ -197,10 +195,9 @@ public void Should_be_able_to_retrieve_stored_Policy_by_interface_using_TryGet() { ISyncPolicy policy = Policy.HandleResult(ResultPrimitive.Fault).Retry(); string key = Guid.NewGuid().ToString(); - ISyncPolicy outPolicy = null; _registry.Add(key, policy); - _registry.TryGet(key, out outPolicy).Should().BeTrue(); + _registry.TryGet(key, out ISyncPolicy outPolicy).Should().BeTrue(); outPolicy.Should().BeSameAs(policy); } @@ -211,7 +208,7 @@ public void Should_be_able_to_retrieve_stored_Policy_using_Get() string key = Guid.NewGuid().ToString(); _registry.Add(key, policy); - _registry.Get(key).Should().BeSameAs(policy); + _registry.Get(key).Should().BeSameAs(policy); } [Fact] @@ -221,7 +218,7 @@ public void Should_be_able_to_retrieve_stored_PolicyTResult_using_Get() string key = Guid.NewGuid().ToString(); _registry.Add(key, policy); - _registry.Get>(key).Should().BeSameAs(policy); + _registry.Get>(key).Should().BeSameAs(policy); } [Fact] @@ -308,7 +305,7 @@ public void Should_throw_while_retrieving_using_Get_when_key_does_not_exist() { string key = Guid.NewGuid().ToString(); ISyncPolicy policy = null; - _registry.Invoking(r => policy = r.Get(key)) + _registry.Invoking(r => policy = r.Get(key)) .Should().Throw(); } @@ -317,7 +314,7 @@ public void Should_throw_while_retrieving_using_GetTResult_when_key_does_not_exi { string key = Guid.NewGuid().ToString(); ISyncPolicy policy = null; - _registry.Invoking(r => policy = r.Get>(key)) + _registry.Invoking(r => policy = r.Get>(key)) .Should().Throw(); } @@ -345,7 +342,7 @@ public void Should_throw_when_retrieving_using_Get_when_key_is_null() { string key = null; ISyncPolicy policy = null; - _registry.Invoking(r => policy = r.Get(key)) + _registry.Invoking(r => policy = r.Get(key)) .Should().Throw(); } @@ -354,7 +351,7 @@ public void Should_throw_when_retrieving_using_GetTResult_when_key_is_null() { string key = null; ISyncPolicy policy = null; - _registry.Invoking(r => policy = r.Get>(key)) + _registry.Invoking(r => policy = r.Get>(key)) .Should().Throw(); } diff --git a/src/Polly.Specs/Registry/ReadOnlyPolicyRegistrySpecs.cs b/src/Polly.Specs/Registry/ReadOnlyPolicyRegistrySpecs.cs index 10b25f688ef..4f698ad3c02 100644 --- a/src/Polly.Specs/Registry/ReadOnlyPolicyRegistrySpecs.cs +++ b/src/Polly.Specs/Registry/ReadOnlyPolicyRegistrySpecs.cs @@ -10,9 +10,9 @@ namespace Polly.Specs.Registry { public class ReadOnlyPolicyRegistrySpecs { - IPolicyRegistry _registry; + readonly IPolicyRegistry _registry; - IReadOnlyPolicyRegistry ReadOnlyRegistry { get{ return _registry; } } + IReadOnlyPolicyRegistry ReadOnlyRegistry => _registry; public ReadOnlyPolicyRegistrySpecs() { @@ -26,10 +26,9 @@ public void Should_be_able_to_retrieve_stored_Policy_using_TryGet() { ISyncPolicy policy = Policy.NoOp(); string key = Guid.NewGuid().ToString(); - ISyncPolicy outPolicy = null; _registry.Add(key, policy); - ReadOnlyRegistry.TryGet(key, out outPolicy).Should().BeTrue(); + ReadOnlyRegistry.TryGet(key, out ISyncPolicy outPolicy).Should().BeTrue(); outPolicy.Should().BeSameAs(policy); } @@ -38,10 +37,9 @@ public void Should_be_able_to_retrieve_stored_PolicyTResult_using_TryGet() { ISyncPolicy policy = Policy.HandleResult(ResultPrimitive.Fault).Retry(); string key = Guid.NewGuid().ToString(); - ISyncPolicy outPolicy = null; _registry.Add(key, policy); - ReadOnlyRegistry.TryGet(key, out outPolicy).Should().BeTrue(); + ReadOnlyRegistry.TryGet(key, out ISyncPolicy outPolicy).Should().BeTrue(); outPolicy.Should().BeSameAs(policy); } @@ -50,10 +48,9 @@ public void Should_be_able_to_retrieve_stored_Policy_by_interface_using_TryGet() { ISyncPolicy policy = Policy.HandleResult(ResultPrimitive.Fault).Retry(); string key = Guid.NewGuid().ToString(); - ISyncPolicy outPolicy = null; _registry.Add(key, policy); - ReadOnlyRegistry.TryGet(key, out outPolicy).Should().BeTrue(); + ReadOnlyRegistry.TryGet(key, out ISyncPolicy outPolicy).Should().BeTrue(); outPolicy.Should().BeSameAs(policy); } @@ -64,7 +61,7 @@ public void Should_be_able_to_retrieve_stored_Policy_using_Get() string key = Guid.NewGuid().ToString(); _registry.Add(key, policy); - ReadOnlyRegistry.Get(key).Should().BeSameAs(policy); + ReadOnlyRegistry.Get(key).Should().BeSameAs(policy); } [Fact] @@ -74,7 +71,7 @@ public void Should_be_able_to_retrieve_stored_PolicyTResult_using_Get() string key = Guid.NewGuid().ToString(); _registry.Add(key, policy); - ReadOnlyRegistry.Get>(key).Should().BeSameAs(policy); + ReadOnlyRegistry.Get>(key).Should().BeSameAs(policy); } [Fact] @@ -121,10 +118,9 @@ public void Should_be_able_to_retrieve_stored_Policy_by_interface_using_Indexer( public void Should_not_throw_while_retrieving_when_key_does_not_exist_using_TryGet() { string key = Guid.NewGuid().ToString(); - ISyncPolicy outPolicy = null; bool result = false; - ReadOnlyRegistry.Invoking(r => result = r.TryGet(key, out outPolicy)) + ReadOnlyRegistry.Invoking(r => result = r.TryGet(key, out ISyncPolicy _)) .Should().NotThrow(); result.Should().BeFalse(); @@ -134,10 +130,9 @@ public void Should_not_throw_while_retrieving_when_key_does_not_exist_using_TryG public void Should_not_throw_while_retrieving_when_key_does_not_exist_using_TryGetPolicyTResult() { string key = Guid.NewGuid().ToString(); - ISyncPolicy outPolicy = null; bool result = false; - ReadOnlyRegistry.Invoking(r => result = r.TryGet(key, out outPolicy)) + ReadOnlyRegistry.Invoking(r => result = r.TryGet(key, out ISyncPolicy _)) .Should().NotThrow(); result.Should().BeFalse(); @@ -147,10 +142,9 @@ public void Should_not_throw_while_retrieving_when_key_does_not_exist_using_TryG public void Should_not_throw_while_retrieving_when_key_does_not_exist_using_TryGetPolicy_by_interface() { string key = Guid.NewGuid().ToString(); - ISyncPolicy outPolicy = null; bool result = false; - ReadOnlyRegistry.Invoking(r => result = r.TryGet>(key, out outPolicy)) + ReadOnlyRegistry.Invoking(r => result = r.TryGet>(key, out _)) .Should().NotThrow(); result.Should().BeFalse(); @@ -161,7 +155,7 @@ public void Should_throw_while_retrieving_using_Get_when_key_does_not_exist() { string key = Guid.NewGuid().ToString(); ISyncPolicy policy = null; - ReadOnlyRegistry.Invoking(r => policy = r.Get(key)) + ReadOnlyRegistry.Invoking(r => policy = r.Get(key)) .Should().Throw(); } @@ -170,7 +164,7 @@ public void Should_throw_while_retrieving_using_GetTResult_when_key_does_not_exi { string key = Guid.NewGuid().ToString(); ISyncPolicy policy = null; - ReadOnlyRegistry.Invoking(r => policy = r.Get>(key)) + ReadOnlyRegistry.Invoking(r => policy = r.Get>(key)) .Should().Throw(); } @@ -198,7 +192,7 @@ public void Should_throw_when_retrieving_using_Get_when_key_is_null() { string key = null; ISyncPolicy policy = null; - ReadOnlyRegistry.Invoking(r => policy = r.Get(key)) + ReadOnlyRegistry.Invoking(r => policy = r.Get(key)) .Should().Throw(); } @@ -207,7 +201,7 @@ public void Should_throw_when_retrieving_using_GetTResult_when_key_is_null() { string key = null; ISyncPolicy policy = null; - ReadOnlyRegistry.Invoking(r => policy = r.Get>(key)) + ReadOnlyRegistry.Invoking(r => policy = r.Get>(key)) .Should().Throw(); } diff --git a/src/Polly.Specs/Retry/RetryAsyncSpecs.cs b/src/Polly.Specs/Retry/RetryAsyncSpecs.cs index 31c5b50c62e..2e0fd91786b 100644 --- a/src/Polly.Specs/Retry/RetryAsyncSpecs.cs +++ b/src/Polly.Specs/Retry/RetryAsyncSpecs.cs @@ -5,7 +5,6 @@ using System.Threading.Tasks; using FluentAssertions; using Polly.Specs.Helpers; -using Polly.Utilities; using Xunit; using Scenario = Polly.Specs.Helpers.IAsyncPolicyExtensions.ExceptionAndOrCancellationScenario; diff --git a/src/Polly.Specs/Retry/RetryForeverAsyncSpecs.cs b/src/Polly.Specs/Retry/RetryForeverAsyncSpecs.cs index e2e2b20117c..d3e5eb165f8 100644 --- a/src/Polly.Specs/Retry/RetryForeverAsyncSpecs.cs +++ b/src/Polly.Specs/Retry/RetryForeverAsyncSpecs.cs @@ -5,7 +5,6 @@ using System.Threading.Tasks; using FluentAssertions; using Polly.Specs.Helpers; -using Polly.Utilities; using Xunit; using Scenario = Polly.Specs.Helpers.IAsyncPolicyExtensions.ExceptionAndOrCancellationScenario; diff --git a/src/Polly.Specs/Retry/RetryTResultSpecsAsync.cs b/src/Polly.Specs/Retry/RetryTResultSpecsAsync.cs index 515dc39dec4..e4ff4c6d6ce 100644 --- a/src/Polly.Specs/Retry/RetryTResultSpecsAsync.cs +++ b/src/Polly.Specs/Retry/RetryTResultSpecsAsync.cs @@ -5,7 +5,6 @@ using System.Threading.Tasks; using FluentAssertions; using Polly.Specs.Helpers; -using Polly.Utilities; using Xunit; using Scenario = Polly.Specs.Helpers.IAsyncPolicyTResultExtensions.ResultAndOrCancellationScenario; diff --git a/src/Polly.Specs/Wrap/PolicyWrapContextAndKeySpecsAsync.cs b/src/Polly.Specs/Wrap/PolicyWrapContextAndKeySpecsAsync.cs index db17d0578a5..e3f87e9a7cb 100644 --- a/src/Polly.Specs/Wrap/PolicyWrapContextAndKeySpecsAsync.cs +++ b/src/Polly.Specs/Wrap/PolicyWrapContextAndKeySpecsAsync.cs @@ -2,7 +2,6 @@ using System.Threading.Tasks; using FluentAssertions; using Polly.Specs.Helpers; -using Polly.Utilities; using Xunit; namespace Polly.Specs.Wrap diff --git a/src/Polly.Specs/Wrap/PolicyWrapSpecs.cs b/src/Polly.Specs/Wrap/PolicyWrapSpecs.cs index 407ed196a78..a6dbce90c14 100644 --- a/src/Polly.Specs/Wrap/PolicyWrapSpecs.cs +++ b/src/Polly.Specs/Wrap/PolicyWrapSpecs.cs @@ -11,103 +11,6 @@ namespace Polly.Specs.Wrap [Collection(Constants.SystemClockDependentTestCollection)] public class PolicyWrapSpecs { - #region Instance configuration syntax tests, non-generic outer - - [Fact] - public void Nongeneric_wraps_nongeneric_instance_syntax_wrapping_null_should_throw() - { - ISyncPolicy retry = Policy.Handle().Retry(1); - - Action config = () => retry.Wrap((Policy)null); - - config.Should().Throw().And.ParamName.Should().Be("innerPolicy"); - } - - [Fact] - public void Nongeneric_wraps_generic_instance_syntax_wrapping_null_should_throw() - { - ISyncPolicy retry = Policy.Handle().Retry(1); - - Action config = () => retry.Wrap((Policy)null); - - config.Should().Throw().And.ParamName.Should().Be("innerPolicy"); - } - - [Fact] - public void Nongeneric_wraps_nongeneric_using_instance_wrap_syntax_should_set_outer_inner() - { - ISyncPolicy policyA = Policy.NoOp(); - ISyncPolicy policyB = Policy.NoOp(); - - ISyncPolicyWrap wrap = policyA.Wrap(policyB); - - wrap.Outer.Should().BeSameAs(policyA); - wrap.Inner.Should().BeSameAs(policyB); - } - - [Fact] - public void Nongeneric_wraps_generic_using_instance_wrap_syntax_should_set_outer_inner() - { - ISyncPolicy policyA = Policy.NoOp(); - ISyncPolicy policyB = Policy.NoOp(); - - ISyncPolicyWrap wrap = policyA.Wrap(policyB); - - wrap.Outer.Should().BeSameAs(policyA); - wrap.Inner.Should().BeSameAs(policyB); - } - - #endregion - - #region Instance configuration syntax tests, generic outer - - [Fact] - public void Generic_wraps_nongeneric_instance_syntax_wrapping_null_should_throw() - { - ISyncPolicy retry = Policy.HandleResult(0).Retry(1); - - Action config = () => retry.Wrap((Policy)null); - - config.Should().Throw().And.ParamName.Should().Be("innerPolicy"); - } - - - [Fact] - public void Generic_wraps_generic_instance_syntax_wrapping_null_should_throw() - { - ISyncPolicy retry = Policy.HandleResult(0).Retry(1); - - Action config = () => retry.Wrap((Policy)null); - - config.Should().Throw().And.ParamName.Should().Be("innerPolicy"); - } - - [Fact] - public void Generic_wraps_nongeneric_using_instance_wrap_syntax_should_set_outer_inner() - { - ISyncPolicy policyA = Policy.NoOp(); - ISyncPolicy policyB = Policy.NoOp(); - - ISyncPolicyWrap wrap = policyA.Wrap(policyB); - - wrap.Outer.Should().BeSameAs(policyA); - wrap.Inner.Should().BeSameAs(policyB); - } - - [Fact] - public void Generic_wraps_generic_using_instance_wrap_syntax_should_set_outer_inner() - { - ISyncPolicy policyA = Policy.NoOp(); - ISyncPolicy policyB = Policy.NoOp(); - - ISyncPolicyWrap wrap = policyA.Wrap(policyB); - - wrap.Outer.Should().BeSameAs(policyA); - wrap.Inner.Should().BeSameAs(policyB); - } - - #endregion - #region Interface extension configuration syntax tests, non-generic outer [Fact] @@ -137,7 +40,7 @@ public void Nongeneric_interface_wraps_nongeneric_instance_syntax_wrapping_null_ { ISyncPolicy retry = Policy.Handle().Retry(1); - Action config = () => retry.Wrap((Policy)null); + Action config = () => retry.Wrap((ISyncPolicy)null); config.Should().Throw().And.ParamName.Should().Be("innerPolicy"); } @@ -147,7 +50,7 @@ public void Nongeneric_interface_wraps_generic_instance_syntax_wrapping_null_sho { ISyncPolicy retry = Policy.Handle().Retry(1); - Action config = () => retry.Wrap((Policy)null); + Action config = () => retry.Wrap((ISyncPolicy)null); config.Should().Throw().And.ParamName.Should().Be("innerPolicy"); } @@ -207,7 +110,7 @@ public void Generic_interface_wraps_nongeneric_instance_syntax_wrapping_null_sho { ISyncPolicy retry = Policy.HandleResult(0).Retry(1); - Action config = () => retry.Wrap((Policy)null); + Action config = () => retry.Wrap((ISyncPolicy)null); config.Should().Throw().And.ParamName.Should().Be("innerPolicy"); } @@ -217,7 +120,7 @@ public void Generic_interface_wraps_generic_instance_syntax_wrapping_null_should { ISyncPolicy retry = Policy.HandleResult(0).Retry(1); - Action config = () => retry.Wrap((Policy)null); + Action config = () => retry.Wrap((ISyncPolicy)null); config.Should().Throw().And.ParamName.Should().Be("innerPolicy"); } diff --git a/src/Polly.Specs/Wrap/PolicyWrapSpecsAsync.cs b/src/Polly.Specs/Wrap/PolicyWrapSpecsAsync.cs index df59d9376ff..8dd0625da73 100644 --- a/src/Polly.Specs/Wrap/PolicyWrapSpecsAsync.cs +++ b/src/Polly.Specs/Wrap/PolicyWrapSpecsAsync.cs @@ -11,102 +11,6 @@ namespace Polly.Specs.Wrap [Collection(Constants.SystemClockDependentTestCollection)] public class PolicyWrapSpecsAsync { - #region Instance configuration syntax tests, non-generic outer - - [Fact] - public void Nongeneric_wraps_nongeneric_instance_syntax_wrapping_null_should_throw() - { - var retry = Policy.Handle().RetryAsync(1); - - Action config = () => retry.WrapAsync((AsyncPolicy)null); - - config.Should().Throw().And.ParamName.Should().Be("innerPolicy"); - } - - [Fact] - public void Nongeneric_wraps_generic_instance_syntax_wrapping_null_should_throw() - { - var retry = Policy.Handle().RetryAsync(1); - - Action config = () => retry.WrapAsync((AsyncPolicy)null); - - config.Should().Throw().And.ParamName.Should().Be("innerPolicy"); - } - - [Fact] - public void Nongeneric_wraps_nongeneric_using_instance_wrap_syntax_should_set_outer_inner() - { - IAsyncPolicy policyA = Policy.NoOpAsync(); - IAsyncPolicy policyB = Policy.NoOpAsync(); - - IAsyncPolicyWrap wrap = policyA.WrapAsync(policyB); - - wrap.Outer.Should().BeSameAs(policyA); - wrap.Inner.Should().BeSameAs(policyB); - } - - [Fact] - public void Nongeneric_wraps_generic_using_instance_wrap_syntax_should_set_outer_inner() - { - IAsyncPolicy policyA = Policy.NoOpAsync(); - IAsyncPolicy policyB = Policy.NoOpAsync(); - - IAsyncPolicyWrap wrap = policyA.WrapAsync(policyB); - - wrap.Outer.Should().BeSameAs(policyA); - wrap.Inner.Should().BeSameAs(policyB); - } - - #endregion - - #region Instance configuration syntax tests, generic outer - - [Fact] - public void Generic_wraps_nongeneric_instance_syntax_wrapping_null_should_throw() - { - var retry = Policy.HandleResult(0).RetryAsync(1); - - Action config = () => retry.WrapAsync((AsyncPolicy)null); - - config.Should().Throw().And.ParamName.Should().Be("innerPolicy"); - } - - [Fact] - public void Generic_wraps_generic_instance_syntax_wrapping_null_should_throw() - { - var retry = Policy.HandleResult(0).RetryAsync(1); - - Action config = () => retry.WrapAsync((AsyncPolicy)null); - - config.Should().Throw().And.ParamName.Should().Be("innerPolicy"); - } - - [Fact] - public void Generic_wraps_nongeneric_using_instance_wrap_syntax_should_set_outer_inner() - { - IAsyncPolicy policyA = Policy.NoOpAsync(); - IAsyncPolicy policyB = Policy.NoOpAsync(); - - IAsyncPolicyWrap wrap = policyA.WrapAsync(policyB); - - wrap.Outer.Should().BeSameAs(policyA); - wrap.Inner.Should().BeSameAs(policyB); - } - - [Fact] - public void Generic_wraps_generic_using_instance_wrap_syntax_should_set_outer_inner() - { - IAsyncPolicy policyA = Policy.NoOpAsync(); - IAsyncPolicy policyB = Policy.NoOpAsync(); - - IAsyncPolicyWrap wrap = policyA.WrapAsync(policyB); - - wrap.Outer.Should().BeSameAs(policyA); - wrap.Inner.Should().BeSameAs(policyB); - } - - #endregion - #region Interface extension configuration syntax tests, non-generic outer [Fact] @@ -136,7 +40,7 @@ public void Nongeneric_interface_wraps_nongeneric_instance_syntax_wrapping_null_ { IAsyncPolicy retry = Policy.Handle().RetryAsync(1); - Action config = () => retry.WrapAsync((AsyncPolicy)null); + Action config = () => retry.WrapAsync((IAsyncPolicy)null); config.Should().Throw().And.ParamName.Should().Be("innerPolicy"); } @@ -146,7 +50,7 @@ public void Nongeneric_interface_wraps_generic_instance_syntax_wrapping_null_sho { IAsyncPolicy retry = Policy.Handle().RetryAsync(1); - Action config = () => retry.WrapAsync((AsyncPolicy)null); + Action config = () => retry.WrapAsync((IAsyncPolicy)null); config.Should().Throw().And.ParamName.Should().Be("innerPolicy"); } @@ -206,7 +110,7 @@ public void Generic_interface_wraps_nongeneric_instance_syntax_wrapping_null_sho { IAsyncPolicy retry = Policy.HandleResult(0).RetryAsync(1); - Action config = () => retry.WrapAsync((AsyncPolicy)null); + Action config = () => retry.WrapAsync((IAsyncPolicy)null); config.Should().Throw().And.ParamName.Should().Be("innerPolicy"); } @@ -216,7 +120,7 @@ public void Generic_interface_wraps_generic_instance_syntax_wrapping_null_should { IAsyncPolicy retry = Policy.HandleResult(0).RetryAsync(1); - Action config = () => retry.WrapAsync((AsyncPolicy)null); + Action config = () => retry.WrapAsync((IAsyncPolicy)null); config.Should().Throw().And.ParamName.Should().Be("innerPolicy"); } diff --git a/src/Polly/AsyncExecutables.cs b/src/Polly/AsyncExecutables.cs new file mode 100644 index 00000000000..5b5ffc72818 --- /dev/null +++ b/src/Polly/AsyncExecutables.cs @@ -0,0 +1,258 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Polly +{ + /// + internal readonly struct AsyncExecutableActionNoParams : IAsyncExecutable + { + private readonly Func _action; + + public AsyncExecutableActionNoParams(Func action) + { + _action = action; + } + + /// + public readonly async Task ExecuteAsync(Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + await _action().ConfigureAwait(continueOnCapturedContext); + return null; + } + } + + /// + internal readonly struct AsyncExecutableActionOnContext : IAsyncExecutable + { + private readonly Func _action; + + public AsyncExecutableActionOnContext(Func action) + { + _action = action; + } + + /// + public readonly async Task ExecuteAsync(Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + await _action(context).ConfigureAwait(continueOnCapturedContext); + return null; + } + } + + /// + internal readonly struct AsyncExecutableActionOnCancellationToken : IAsyncExecutable + { + private readonly Func _action; + + public AsyncExecutableActionOnCancellationToken(Func action) + { + _action = action; + } + + /// + public readonly async Task ExecuteAsync(Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + await _action(cancellationToken).ConfigureAwait(continueOnCapturedContext); + return null; + } + } + + /// + internal readonly struct AsyncExecutableActionOnContextCancellationToken : IAsyncExecutable + { + private readonly Func _action; + + public AsyncExecutableActionOnContextCancellationToken(Func action) + { + _action = action; + } + + /// + public readonly async Task ExecuteAsync(Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + await _action(context, cancellationToken).ConfigureAwait(continueOnCapturedContext); + return null; + } + } + + /// + internal readonly struct AsyncExecutableAction : IAsyncExecutable + { + private readonly Func _action; + + public AsyncExecutableAction(Func action) + { + _action = action; + } + + /// + public readonly async Task ExecuteAsync(Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + await _action(context, cancellationToken, continueOnCapturedContext).ConfigureAwait(continueOnCapturedContext); + return null; + } + } + + internal readonly struct AsyncExecutableAction : IAsyncExecutable + { + private readonly Func _action; + private readonly T1 _arg1; + + public AsyncExecutableAction(Func action, T1 arg1) + { + _action = action; + _arg1 = arg1; + } + + public readonly async Task ExecuteAsync(Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + await _action(context, cancellationToken, continueOnCapturedContext, _arg1).ConfigureAwait(continueOnCapturedContext); + return null; + } + } + + internal readonly struct AsyncExecutableAction : IAsyncExecutable + { + private readonly Func _action; + private readonly T1 _arg1; + private readonly T2 _arg2; + + public AsyncExecutableAction(Func action, T1 arg1, T2 arg2) + { + _action = action; + _arg1 = arg1; + _arg2 = arg2; + } + + public readonly async Task ExecuteAsync(Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + await _action(context, cancellationToken, continueOnCapturedContext, _arg1, _arg2).ConfigureAwait(continueOnCapturedContext); + return null; + } + } + + /// + internal readonly struct AsyncExecutableFuncNoParams : IAsyncExecutable + { + private readonly Func> _func; + + /// + /// Creates a struct for the passed func, which may be executed through a policy at a later point in time. + /// + /// The function. + public AsyncExecutableFuncNoParams(Func> func) + { + _func = func; + } + + /// + public readonly Task ExecuteAsync(Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) => _func(); + } + + /// + internal readonly struct AsyncExecutableFuncOnContext : IAsyncExecutable + { + private readonly Func> _func; + + /// + /// Creates a struct for the passed func, which may be executed through a policy at a later point in time. + /// + /// The function. + public AsyncExecutableFuncOnContext(Func> func) + { + _func = func; + } + + /// + public readonly Task ExecuteAsync(Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) => _func(context); + } + + /// + internal readonly struct AsyncExecutableFuncOnCancellationToken : IAsyncExecutable + { + private readonly Func> _func; + + /// + /// Creates a struct for the passed func, which may be executed through a policy at a later point in time. + /// + /// The function. + public AsyncExecutableFuncOnCancellationToken(Func> func) + { + _func = func; + } + + /// + public readonly Task ExecuteAsync(Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) => _func(cancellationToken); + } + + /// + internal readonly struct AsyncExecutableFuncOnContextCancellationToken : IAsyncExecutable + { + private readonly Func> _func; + + /// + /// Creates a struct for the passed func, which may be executed through a policy at a later point in time. + /// + /// The function. + public AsyncExecutableFuncOnContextCancellationToken(Func> func) + { + _func = func; + } + + /// + public readonly Task ExecuteAsync(Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) => _func(context, cancellationToken); + } + + /// + internal readonly struct AsyncExecutableFunc : IAsyncExecutable + { + private readonly Func> _func; + + /// + /// Creates a struct for the passed func, which may be executed through a policy at a later point in time. + /// + /// The function. + public AsyncExecutableFunc(Func> func) + { + _func = func; + } + + /// + public readonly Task ExecuteAsync(Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) => _func(context, cancellationToken, continueOnCapturedContext); + } + + /// + internal readonly struct AsyncExecutableFunc : IAsyncExecutable + { + private readonly Func> _func; + private readonly T1 _arg1; + + public AsyncExecutableFunc(Func> func, T1 arg1) + { + _func = func; + _arg1 = arg1; + } + + /// + public readonly Task ExecuteAsync(Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) => _func(context, cancellationToken, continueOnCapturedContext, _arg1); + } + + /// + internal readonly struct AsyncExecutableFunc : IAsyncExecutable + { + private readonly Func> _func; + private readonly T1 _arg1; + private readonly T2 _arg2; + + public AsyncExecutableFunc(Func> func, T1 arg1, T2 arg2) + { + _func = func; + _arg1 = arg1; + _arg2 = arg2; + } + + /// + public readonly Task ExecuteAsync(Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) => _func(context, cancellationToken, continueOnCapturedContext, _arg1, _arg2); + } +} diff --git a/src/Polly/AsyncPolicy.ExecuteOverloads.cs b/src/Polly/AsyncPolicy.ExecuteOverloads.cs deleted file mode 100644 index d552a3e46a9..00000000000 --- a/src/Polly/AsyncPolicy.ExecuteOverloads.cs +++ /dev/null @@ -1,480 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Threading; -using System.Threading.Tasks; - -namespace Polly -{ - public abstract partial class AsyncPolicy : PolicyBase, IAsyncPolicy - { - #region ExecuteAsync overloads - - /// - /// Executes the specified asynchronous action within the policy. - /// - /// The action to perform. - [DebuggerStepThrough] - public Task ExecuteAsync(Func action) - => ExecuteAsync((ctx, ct) => action(), new Context(), DefaultCancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy. - /// - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - [DebuggerStepThrough] - public Task ExecuteAsync(Func action, IDictionary contextData) - => ExecuteAsync((ctx, ct) => action(ctx), new Context(contextData), DefaultCancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy. - /// - /// The action to perform. - /// Context data that is passed to the exception policy. - [DebuggerStepThrough] - public Task ExecuteAsync(Func action, Context context) - => ExecuteAsync((ctx, ct) => action(ctx), context, DefaultCancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy. - /// - /// The action to perform. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - [DebuggerStepThrough] - public Task ExecuteAsync(Func action, CancellationToken cancellationToken) - => ExecuteAsync((ctx, ct) => action(ct), new Context(), cancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy. - /// - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - [DebuggerStepThrough] - public Task ExecuteAsync(Func action, IDictionary contextData, CancellationToken cancellationToken) - => ExecuteAsync(action, new Context(contextData), cancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy. - /// - /// The action to perform. - /// Context data that is passed to the exception policy. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - [DebuggerStepThrough] - public Task ExecuteAsync(Func action, Context context, CancellationToken cancellationToken) - => ExecuteAsync(action, context, cancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy. - /// - /// The action to perform. - /// Whether to continue on a captured synchronization context. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - /// Please use asynchronous-defined policies when calling asynchronous ExecuteAsync (and similar) methods. - [DebuggerStepThrough] - public Task ExecuteAsync(Func action, CancellationToken cancellationToken, bool continueOnCapturedContext) - => ExecuteAsync((ctx, ct) => action(ct), new Context(), cancellationToken, continueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy. - /// - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - /// Whether to continue on a captured synchronization context. - /// contextData - [DebuggerStepThrough] - public Task ExecuteAsync(Func action, IDictionary contextData, CancellationToken cancellationToken, bool continueOnCapturedContext) - => ExecuteAsync(action, new Context(contextData), cancellationToken, continueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy. - /// - /// The action to perform. - /// Context data that is passed to the exception policy. - /// Whether to continue on a captured synchronization context. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - /// Please use asynchronous-defined policies when calling asynchronous ExecuteAsync (and similar) methods. - [DebuggerStepThrough] - public async Task ExecuteAsync(Func action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) - { - if (context == null) throw new ArgumentNullException(nameof(context)); - - SetPolicyContext(context, out string priorPolicyWrapKey, out string priorPolicyKey); - - try - { - await ImplementationAsync(action, context, cancellationToken, continueOnCapturedContext).ConfigureAwait(continueOnCapturedContext); - } - finally - { - RestorePolicyContext(context, priorPolicyWrapKey, priorPolicyKey); - } - } - - #region Overloads method-generic in TResult - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The type of the result. - /// The action to perform. - /// The value returned by the action - [DebuggerStepThrough] - public Task ExecuteAsync(Func> action) - => ExecuteAsync((ctx, ct) => action(), new Context(), DefaultCancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - /// The value returned by the action - [DebuggerStepThrough] - public Task ExecuteAsync(Func> action, IDictionary contextData) - => ExecuteAsync((ctx, ct) => action(ctx), new Context(contextData), DefaultCancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The type of the result. - /// The action to perform. - /// Context data that is passed to the exception policy. - /// The value returned by the action - [DebuggerStepThrough] - public Task ExecuteAsync(Func> action, Context context) - => ExecuteAsync((ctx, ct) => action(ctx), context, DefaultCancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The type of the result. - /// The action to perform. - /// A cancellation token which can be used to cancel the action. When a retry policy is in use, also cancels any further retries. - /// The value returned by the action - [DebuggerStepThrough] - public Task ExecuteAsync(Func> action, CancellationToken cancellationToken) - => ExecuteAsync((ctx, ct) => action(ct), new Context(), cancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - /// The value returned by the action - [DebuggerStepThrough] - public Task ExecuteAsync(Func> action, IDictionary contextData, CancellationToken cancellationToken) - => ExecuteAsync(action, new Context(contextData), cancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The type of the result. - /// The action to perform. - /// Context data that is passed to the exception policy. - /// A cancellation token which can be used to cancel the action. When a retry policy is in use, also cancels any further retries. - /// The value returned by the action - [DebuggerStepThrough] - public Task ExecuteAsync(Func> action, Context context, CancellationToken cancellationToken) - => ExecuteAsync(action, context, cancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The type of the result. - /// The action to perform. - /// Whether to continue on a captured synchronization context. - /// A cancellation token which can be used to cancel the action. When a retry policy is in use, also cancels any further retries. - /// The value returned by the action - /// Please use asynchronous-defined policies when calling asynchronous ExecuteAsync (and similar) methods. - [DebuggerStepThrough] - public Task ExecuteAsync(Func> action, CancellationToken cancellationToken, bool continueOnCapturedContext) - => ExecuteAsync((ctx, ct) => action(ct), new Context(), cancellationToken, continueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - /// Whether to continue on a captured synchronization context. - /// The value returned by the action - /// contextData - [DebuggerStepThrough] - public Task ExecuteAsync(Func> action, IDictionary contextData, CancellationToken cancellationToken, bool continueOnCapturedContext) - => ExecuteAsync(action, new Context(contextData), cancellationToken, continueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The type of the result. - /// The action to perform. - /// Context data that is passed to the exception policy. - /// Whether to continue on a captured synchronization context. - /// A cancellation token which can be used to cancel the action. When a retry policy is in use, also cancels any further retries. - /// The value returned by the action - /// Please use asynchronous-defined policies when calling asynchronous ExecuteAsync (and similar) methods. - [DebuggerStepThrough] - public async Task ExecuteAsync(Func> action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) - { - if (context == null) throw new ArgumentNullException(nameof(context)); - - SetPolicyContext(context, out string priorPolicyWrapKey, out string priorPolicyKey); - - try - { - return await ImplementationAsync(action, context, cancellationToken, continueOnCapturedContext).ConfigureAwait(continueOnCapturedContext); - } - finally - { - RestorePolicyContext(context, priorPolicyWrapKey, priorPolicyKey); - } - } - - #endregion - - #endregion - - #region ExecuteAndCaptureAsync overloads - - /// - /// Executes the specified asynchronous action within the policy and returns the captured result. - /// - /// The action to perform. - /// The captured result - [DebuggerStepThrough] - public Task ExecuteAndCaptureAsync(Func action) - => ExecuteAndCaptureAsync((ctx, ct) => action(), new Context(), DefaultCancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the captured result. - /// - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - /// contextData - /// The captured result - [DebuggerStepThrough] - public Task ExecuteAndCaptureAsync(Func action, IDictionary contextData) - => ExecuteAndCaptureAsync((ctx, ct) => action(ctx), new Context(contextData), DefaultCancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the captured result. - /// - /// The action to perform. - /// Context data that is passed to the exception policy. - /// The captured result - [DebuggerStepThrough] - public Task ExecuteAndCaptureAsync(Func action, Context context) - => ExecuteAndCaptureAsync((ctx, ct) => action(ctx), context, DefaultCancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the captured result. - /// - /// The action to perform. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - [DebuggerStepThrough] - public Task ExecuteAndCaptureAsync(Func action, CancellationToken cancellationToken) - => ExecuteAndCaptureAsync((ctx, ct) => action(ct), new Context(), cancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the captured result. - /// - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - /// contextData - /// The captured result - [DebuggerStepThrough] - public Task ExecuteAndCaptureAsync(Func action, IDictionary contextData, CancellationToken cancellationToken) - => ExecuteAndCaptureAsync(action, new Context(contextData), cancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the captured result. - /// - /// The action to perform. - /// Context data that is passed to the exception policy. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - [DebuggerStepThrough] - public Task ExecuteAndCaptureAsync(Func action, Context context, CancellationToken cancellationToken) - => ExecuteAndCaptureAsync(action, context, cancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the captured result. - /// - /// The action to perform. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - /// Whether to continue on a captured synchronization context. - /// Please use asynchronous-defined policies when calling asynchronous ExecuteAsync (and similar) methods. - [DebuggerStepThrough] - public Task ExecuteAndCaptureAsync(Func action, CancellationToken cancellationToken, bool continueOnCapturedContext) - => ExecuteAndCaptureAsync((ctx, ct) => action(ct), new Context(), cancellationToken, continueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the captured result. - /// - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - /// Whether to continue on a captured synchronization context. - /// contextData - /// The captured result - [DebuggerStepThrough] - public Task ExecuteAndCaptureAsync(Func action, IDictionary contextData, CancellationToken cancellationToken, bool continueOnCapturedContext) - => ExecuteAndCaptureAsync(action, new Context(contextData), cancellationToken, continueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the captured result. - /// - /// The action to perform. - /// Context data that is passed to the exception policy. - /// Whether to continue on a captured synchronization context. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - /// Please use asynchronous-defined policies when calling asynchronous ExecuteAsync (and similar) methods. - [DebuggerStepThrough] - public async Task ExecuteAndCaptureAsync(Func action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) - { - if (context == null) throw new ArgumentNullException(nameof(context)); - - try - { - await ExecuteAsync(action, context, cancellationToken, continueOnCapturedContext).ConfigureAwait(continueOnCapturedContext); - return PolicyResult.Successful(context); - } - catch (Exception exception) - { - return PolicyResult.Failure(exception, GetExceptionType(ExceptionPredicates, exception), context); - } - } - - #region Overloads method-generic in TResult - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The type of the result. - /// The action to perform. - /// The captured result - [DebuggerStepThrough] - public Task> ExecuteAndCaptureAsync(Func> action) - => ExecuteAndCaptureAsync((ctx, ct) => action(), new Context(), DefaultCancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The type of the result. - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - /// contextData - /// The captured result - [DebuggerStepThrough] - public Task> ExecuteAndCaptureAsync(Func> action, IDictionary contextData) - => ExecuteAndCaptureAsync((ctx, ct) => action(ctx), new Context(contextData), DefaultCancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The type of the result. - /// The action to perform. - /// Context data that is passed to the exception policy. - /// The captured result - [DebuggerStepThrough] - public Task> ExecuteAndCaptureAsync(Func> action, Context context) - => ExecuteAndCaptureAsync((ctx, ct) => action(ctx), context, DefaultCancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The type of the result. - /// The action to perform. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - /// The captured result - [DebuggerStepThrough] - public Task> ExecuteAndCaptureAsync(Func> action, CancellationToken cancellationToken) - => ExecuteAndCaptureAsync((ctx, ct) => action(ct), new Context(), cancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The type of the result. - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - /// contextData - /// The captured result - [DebuggerStepThrough] - public Task> ExecuteAndCaptureAsync(Func> action, IDictionary contextData, CancellationToken cancellationToken) - => ExecuteAndCaptureAsync(action, new Context(contextData), cancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The type of the result. - /// The action to perform. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - /// The captured result - [DebuggerStepThrough] - public Task> ExecuteAndCaptureAsync(Func> action, Context context, CancellationToken cancellationToken) - => ExecuteAndCaptureAsync(action, context, cancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The type of the result. - /// The action to perform. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - /// Whether to continue on a captured synchronization context. - /// The captured result - /// Please use asynchronous-defined policies when calling asynchronous ExecuteAsync (and similar) methods. - [DebuggerStepThrough] - public Task> ExecuteAndCaptureAsync(Func> action, CancellationToken cancellationToken, bool continueOnCapturedContext) - => ExecuteAndCaptureAsync((ctx, ct) => action(ct), new Context(), cancellationToken, continueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The type of the result. - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - /// Whether to continue on a captured synchronization context. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - /// The captured result - /// contextData - [DebuggerStepThrough] - public Task> ExecuteAndCaptureAsync(Func> action, IDictionary contextData, CancellationToken cancellationToken, bool continueOnCapturedContext) - => ExecuteAndCaptureAsync(action, new Context(contextData), cancellationToken, continueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The type of the result. - /// The action to perform. - /// Context data that is passed to the exception policy. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - /// Whether to continue on a captured synchronization context. - /// The captured result - /// Please use asynchronous-defined policies when calling asynchronous ExecuteAsync (and similar) methods. - [DebuggerStepThrough] - public async Task> ExecuteAndCaptureAsync(Func> action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) - { - if (context == null) throw new ArgumentNullException(nameof(context)); - - try - { - return PolicyResult.Successful( - await ExecuteAsync(action, context, cancellationToken, continueOnCapturedContext).ConfigureAwait(continueOnCapturedContext), context); - } - catch (Exception exception) - { - return PolicyResult.Failure(exception, GetExceptionType(ExceptionPredicates, exception), context); - } - } - - #endregion - - #endregion - - } -} diff --git a/src/Polly/AsyncPolicy.IAsyncPolicy.cs b/src/Polly/AsyncPolicy.IAsyncPolicy.cs new file mode 100644 index 00000000000..2280dff19c0 --- /dev/null +++ b/src/Polly/AsyncPolicy.IAsyncPolicy.cs @@ -0,0 +1,748 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; + +namespace Polly +{ + public abstract partial class AsyncPolicy : IAsyncPolicy + { + #region ExecuteAsync overloads + + /// + /// Executes the specified asynchronous action within the policy. + /// + /// The action to perform. + [DebuggerStepThrough] + public Task ExecuteAsync(Func action) + { + return ((IAsyncPolicyInternal)this).ExecuteAsync(new AsyncExecutableActionNoParams(action), GetDefaultExecutionContext(), DefaultCancellationToken, DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy. + /// + /// The action to perform. + /// Arbitrary data that is passed to the exception policy. + [DebuggerStepThrough] + public Task ExecuteAsync(Func action, IDictionary contextData) + { + return ((IAsyncPolicyInternal)this).ExecuteAsync(new AsyncExecutableActionOnContext(action), new Context(contextData), DefaultCancellationToken, DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy. + /// + /// The action to perform. + /// Context data that is passed to the exception policy. + [DebuggerStepThrough] + public Task ExecuteAsync(Func action, Context context) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAsync(new AsyncExecutableActionOnContext(action), context, DefaultCancellationToken, DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy. + /// + /// The action to perform. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + [DebuggerStepThrough] + public Task ExecuteAsync(Func action, CancellationToken cancellationToken) + { + return ((IAsyncPolicyInternal)this).ExecuteAsync(new AsyncExecutableActionOnCancellationToken(action), GetDefaultExecutionContext(), cancellationToken, DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy. + /// + /// The action to perform. + /// Arbitrary data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + [DebuggerStepThrough] + public Task ExecuteAsync(Func action, IDictionary contextData, CancellationToken cancellationToken) + { + return ((IAsyncPolicyInternal)this).ExecuteAsync(new AsyncExecutableActionOnContextCancellationToken(action), new Context(contextData), cancellationToken, DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy. + /// + /// The action to perform. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + [DebuggerStepThrough] + public Task ExecuteAsync(Func action, Context context, CancellationToken cancellationToken) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAsync(new AsyncExecutableActionOnContextCancellationToken(action), context, cancellationToken, DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy. + /// + /// The action to perform. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + [DebuggerStepThrough] + public Task ExecuteAsync(Func action, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + return ((IAsyncPolicyInternal)this).ExecuteAsync(new AsyncExecutableActionOnCancellationToken(action), GetDefaultExecutionContext(), cancellationToken, continueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy. + /// + /// The action to perform. + /// Arbitrary data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// Whether to continue on a captured synchronization context. + /// contextData + [DebuggerStepThrough] + public Task ExecuteAsync(Func action, IDictionary contextData, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + return ((IAsyncPolicyInternal)this).ExecuteAsync(new AsyncExecutableActionOnContextCancellationToken(action), new Context(contextData), cancellationToken, continueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy. + /// + /// The action to perform. + /// Context data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + [DebuggerStepThrough] + public Task ExecuteAsync(Func action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAsync(new AsyncExecutableActionOnContextCancellationToken(action), context, cancellationToken, continueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy, passing an extra input of user-defined type . + /// + /// The action to perform. + /// Context data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The type of the first custom input to the function. + [DebuggerStepThrough] + public Task ExecuteAsync(Func action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, T1 input1) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAsync(new AsyncExecutableAction(action, input1), context, cancellationToken, continueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy, passing two extra inputs of user-defined types and . + /// + /// The action to perform. + /// Context data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The value of the second custom input to the function. + /// The type of the first custom input to the function. + /// The type of the second custom input to the function. + [DebuggerStepThrough] + public Task ExecuteAsync(Func action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, T1 input1, T2 input2) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAsync(new AsyncExecutableAction(action, input1, input2), context, cancellationToken, continueOnCapturedContext); + } + + #region Overloads method-generic in TResult + + /// + /// Executes the specified asynchronous action within the policy and returns the result. + /// + /// The type of the result. + /// The action to perform. + /// The value returned by the function + [DebuggerStepThrough] + public Task ExecuteAsync(Func> func) + { + return ((IAsyncPolicyInternal)this).ExecuteAsync, TResult>( + new AsyncExecutableFuncNoParams(func), + GetDefaultExecutionContext(), + DefaultCancellationToken, + DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy and returns the result. + /// + /// The action to perform. + /// Arbitrary data that is passed to the exception policy. + /// The value returned by the function + [DebuggerStepThrough] + public Task ExecuteAsync(Func> func, IDictionary contextData) + { + return ((IAsyncPolicyInternal)this).ExecuteAsync, TResult>( + new AsyncExecutableFuncOnContext(func), + new Context(contextData), + DefaultCancellationToken, + DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy and returns the result. + /// + /// The type of the result. + /// The action to perform. + /// Context data that is passed to the exception policy. + /// The value returned by the function + [DebuggerStepThrough] + public Task ExecuteAsync(Func> func, Context context) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAsync, TResult>( + new AsyncExecutableFuncOnContext(func), + context, + DefaultCancellationToken, + DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy and returns the result. + /// + /// The type of the result. + /// The action to perform. + /// A cancellation token which can be used to cancel the action. When a retry policy is in use, also cancels any further retries. + /// The value returned by the function + [DebuggerStepThrough] + public Task ExecuteAsync(Func> func, CancellationToken cancellationToken) + { + return ((IAsyncPolicyInternal)this).ExecuteAsync, TResult>( + new AsyncExecutableFuncOnCancellationToken(func), + GetDefaultExecutionContext(), + cancellationToken, + DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy and returns the result. + /// + /// The action to perform. + /// Arbitrary data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value returned by the function + [DebuggerStepThrough] + public Task ExecuteAsync(Func> func, IDictionary contextData, CancellationToken cancellationToken) + { + return ((IAsyncPolicyInternal)this).ExecuteAsync, TResult>( + new AsyncExecutableFuncOnContextCancellationToken(func), + new Context(contextData), + cancellationToken, + DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy and returns the result. + /// + /// The type of the result. + /// The action to perform. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy is in use, also cancels any further retries. + /// The value returned by the function + [DebuggerStepThrough] + public Task ExecuteAsync(Func> func, Context context, CancellationToken cancellationToken) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAsync, TResult>( + new AsyncExecutableFuncOnContextCancellationToken(func), + context, + cancellationToken, + DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy and returns the result. + /// + /// The type of the result. + /// The action to perform. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy is in use, also cancels any further retries. + /// The value returned by the function + [DebuggerStepThrough] + public Task ExecuteAsync(Func> func, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + return ((IAsyncPolicyInternal)this).ExecuteAsync, TResult>( + new AsyncExecutableFuncOnCancellationToken(func), + GetDefaultExecutionContext(), + cancellationToken, + continueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy and returns the result. + /// + /// The action to perform. + /// Arbitrary data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// Whether to continue on a captured synchronization context. + /// The value returned by the function + /// contextData + [DebuggerStepThrough] + public Task ExecuteAsync(Func> func, IDictionary contextData, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + return ((IAsyncPolicyInternal)this).ExecuteAsync, TResult>( + new AsyncExecutableFuncOnContextCancellationToken(func), + new Context(contextData), + cancellationToken, + continueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous function within the policy and returns the result. + /// + /// The type of the result. + /// The function to execute. + /// Context data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy is in use, also cancels any further retries. + /// The value returned by the function + [DebuggerStepThrough] + public Task ExecuteAsync(Func> func, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAsync, TResult>( + new AsyncExecutableFuncOnContextCancellationToken(func), + context, + cancellationToken, + continueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous function within the policy, passing an extra input of user-defined type , and returns the result. + /// + /// The type of the result. + /// The function to execute. + /// Context data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The type of the first custom input to the function. + /// The value returned by the function + [DebuggerStepThrough] + public Task ExecuteAsync(Func> func, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, T1 input1) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAsync, TResult>(new AsyncExecutableFunc(func, input1), context, cancellationToken, continueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous function within the policy, passing two extra inputs of user-defined types and , and returns the result. + /// + /// The type of the result. + /// The function to execute. + /// Context data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The value of the second custom input to the function. + /// The type of the first custom input to the function. + /// The type of the second custom input to the function. + /// The value returned by the function + [DebuggerStepThrough] + public Task ExecuteAsync(Func> func, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, T1 input1, T2 input2) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAsync, TResult>(new AsyncExecutableFunc(func, input1, input2), context, cancellationToken, continueOnCapturedContext); + } + + #endregion + + #endregion + + #region ExecuteAndCaptureAsync overloads + + /// + /// Executes the specified asynchronous action within the policy and returns the captured result. + /// + /// The action to perform. + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task ExecuteAndCaptureAsync(Func action) + { + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync(new AsyncExecutableActionNoParams(action), GetDefaultExecutionContext(), DefaultCancellationToken, DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy and returns the captured result. + /// + /// The action to perform. + /// Arbitrary data that is passed to the exception policy. + /// contextData + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task ExecuteAndCaptureAsync(Func action, IDictionary contextData) + { + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync(new AsyncExecutableActionOnContext(action), new Context(contextData), DefaultCancellationToken, DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy and returns the captured result. + /// + /// The action to perform. + /// Context data that is passed to the exception policy. + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task ExecuteAndCaptureAsync(Func action, Context context) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync(new AsyncExecutableActionOnContext(action), context, DefaultCancellationToken, DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy and returns the captured result. + /// + /// The action to perform. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task ExecuteAndCaptureAsync(Func action, CancellationToken cancellationToken) + { + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync(new AsyncExecutableActionOnCancellationToken(action), GetDefaultExecutionContext(), cancellationToken, DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy and returns the captured result. + /// + /// The action to perform. + /// Arbitrary data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// contextData + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task ExecuteAndCaptureAsync(Func action, IDictionary contextData, CancellationToken cancellationToken) + { + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync(new AsyncExecutableActionOnContextCancellationToken(action), new Context(contextData), cancellationToken, DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy and returns the captured result. + /// + /// The action to perform. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task ExecuteAndCaptureAsync(Func action, Context context, CancellationToken cancellationToken) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync(new AsyncExecutableActionOnContextCancellationToken(action), context, cancellationToken, DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy and returns the captured result. + /// + /// The action to perform. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// Whether to continue on a captured synchronization context. + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task ExecuteAndCaptureAsync(Func action, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync(new AsyncExecutableActionOnCancellationToken(action), GetDefaultExecutionContext(), cancellationToken, continueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy and returns the captured result. + /// + /// The action to perform. + /// Arbitrary data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// Whether to continue on a captured synchronization context. + /// contextData + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task ExecuteAndCaptureAsync(Func action, IDictionary contextData, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync(new AsyncExecutableActionOnContextCancellationToken(action), new Context(contextData), cancellationToken, continueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy and returns the captured result. + /// + /// The action to perform. + /// Context data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task ExecuteAndCaptureAsync(Func action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync(new AsyncExecutableActionOnContextCancellationToken(action), context, cancellationToken, continueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy, passing an extra input of user-defined type . + /// + /// The action to perform. + /// Context data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The type of the first custom input to the function. + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task ExecuteAndCaptureAsync(Func action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, T1 input1) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync(new AsyncExecutableAction(action, input1), context, cancellationToken, continueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy, passing two extra inputs of user-defined types and . + /// + /// The action to perform. + /// Context data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The value of the second custom input to the function. + /// The type of the first custom input to the function. + /// The type of the second custom input to the function. + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task ExecuteAndCaptureAsync(Func action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, T1 input1, T2 input2) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync(new AsyncExecutableAction(action, input1, input2), context, cancellationToken, continueOnCapturedContext); + } + + #region Overloads method-generic in TResult + + /// + /// Executes the specified asynchronous function within the policy and returns the result. + /// + /// The type of the result. + /// The function to invoke. + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task> ExecuteAndCaptureAsync(Func> func) + { + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync, TResult>( + new AsyncExecutableFuncNoParams(func), + GetDefaultExecutionContext(), + DefaultCancellationToken, + DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous function within the policy and returns the result. + /// + /// The type of the result. + /// The function to invoke. + /// Arbitrary data that is passed to the exception policy. + /// contextData + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task> ExecuteAndCaptureAsync(Func> func, IDictionary contextData) + { + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync, TResult>( + new AsyncExecutableFuncOnContext(func), + new Context(contextData), + DefaultCancellationToken, + DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous function within the policy and returns the result. + /// + /// The type of the result. + /// The function to invoke. + /// Context data that is passed to the exception policy. + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task> ExecuteAndCaptureAsync(Func> func, Context context) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync, TResult>( + new AsyncExecutableFuncOnContext(func), + context, + DefaultCancellationToken, + DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous function within the policy and returns the result. + /// + /// The type of the result. + /// The function to invoke. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task> ExecuteAndCaptureAsync(Func> func, CancellationToken cancellationToken) + { + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync, TResult>( + new AsyncExecutableFuncOnCancellationToken(func), + GetDefaultExecutionContext(), + cancellationToken, + DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous function within the policy and returns the result. + /// + /// The type of the result. + /// The function to invoke. + /// Arbitrary data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// contextData + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task> ExecuteAndCaptureAsync(Func> func, IDictionary contextData, CancellationToken cancellationToken) + { + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync, TResult>( + new AsyncExecutableFuncOnContextCancellationToken(func), + new Context(contextData), + cancellationToken, + DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous function within the policy and returns the result. + /// + /// The type of the result. + /// The function to invoke. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task> ExecuteAndCaptureAsync(Func> func, Context context, CancellationToken cancellationToken) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync, TResult>( + new AsyncExecutableFuncOnContextCancellationToken(func), + context, + cancellationToken, + DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous function within the policy and returns the result. + /// + /// The type of the result. + /// The function to invoke. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// Whether to continue on a captured synchronization context. + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task> ExecuteAndCaptureAsync(Func> func, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync, TResult>( + new AsyncExecutableFuncOnCancellationToken(func), + GetDefaultExecutionContext(), + cancellationToken, + continueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous function within the policy and returns the result. + /// + /// The type of the result. + /// The function to invoke. + /// Arbitrary data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The outcome of the execution, as a promise of a captured + /// contextData + [DebuggerStepThrough] + public Task> ExecuteAndCaptureAsync(Func> func, IDictionary contextData, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync, TResult>( + new AsyncExecutableFuncOnContextCancellationToken(func), + new Context(contextData), + cancellationToken, + continueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous function within the policy and returns the result. + /// + /// The type of the result. + /// The function to invoke. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// Whether to continue on a captured synchronization context. + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task> ExecuteAndCaptureAsync(Func> func, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync, TResult>( + new AsyncExecutableFuncOnContextCancellationToken(func), + context, + cancellationToken, + continueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous function within the policy, passing an extra input of user-defined type , and returns the captured result. + /// + /// The type of the result. + /// The function to execute. + /// Context data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The type of the first custom input to the function. + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task> ExecuteAndCaptureAsync(Func> func, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, T1 input1) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync, TResult>(new AsyncExecutableFunc(func, input1), context, cancellationToken, continueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous function within the policy, passing two extra inputs of user-defined types and , and returns the result. + /// + /// The type of the result. + /// The function to execute. + /// Context data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The value of the second custom input to the function. + /// The type of the first custom input to the function. + /// The type of the second custom input to the function. + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task> ExecuteAndCaptureAsync(Func> func, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, T1 input1, T2 input2) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync, TResult>(new AsyncExecutableFunc(func, input1, input2), context, cancellationToken, continueOnCapturedContext); + } + + #endregion + + #endregion + + } +} diff --git a/src/Polly/AsyncPolicy.IAsyncPolicyInternal.cs b/src/Polly/AsyncPolicy.IAsyncPolicyInternal.cs new file mode 100644 index 00000000000..fb4fb244789 --- /dev/null +++ b/src/Polly/AsyncPolicy.IAsyncPolicyInternal.cs @@ -0,0 +1,74 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Polly +{ + public abstract partial class AsyncPolicy : IAsyncPolicyInternal + { + async Task IAsyncPolicyInternal.ExecuteAsync(TExecutableAsync action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + SetPolicyContext(context, out string priorPolicyWrapKey, out string priorPolicyKey); + + try + { + await AsyncNonGenericImplementation(action, context, cancellationToken, continueOnCapturedContext) + .ConfigureAwait(continueOnCapturedContext); + } + finally + { + RestorePolicyContext(context, priorPolicyWrapKey, priorPolicyKey); + } + } + + async Task IAsyncPolicyInternal.ExecuteAsync(TExecutableAsync action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + SetPolicyContext(context, out string priorPolicyWrapKey, out string priorPolicyKey); + + try + { + return await AsyncGenericImplementation(action, context, cancellationToken, continueOnCapturedContext) + .ConfigureAwait(continueOnCapturedContext); + } + finally + { + RestorePolicyContext(context, priorPolicyWrapKey, priorPolicyKey); + } + } + + async Task IAsyncPolicyInternal.ExecuteAndCaptureAsync(TExecutableAsync action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + try + { + await ((IAsyncPolicyInternal)this).ExecuteAsync(action, context, cancellationToken, continueOnCapturedContext).ConfigureAwait(continueOnCapturedContext); + return PolicyResult.Successful(context); + } + catch (Exception exception) + { + return PolicyResult.Failure(exception, GetExceptionType(ExceptionPredicates, exception), context); + } + } + + async Task> IAsyncPolicyInternal.ExecuteAndCaptureAsync(TExecutableAsync action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + try + { + return PolicyResult.Successful( + await ((IAsyncPolicyInternal)this).ExecuteAsync(action, context, cancellationToken, continueOnCapturedContext).ConfigureAwait(continueOnCapturedContext), + context); + } + catch (Exception exception) + { + return PolicyResult.Failure(exception, GetExceptionType(ExceptionPredicates, exception), context); + } + } + } +} diff --git a/src/Polly/AsyncPolicy.NonGenericImplementation.cs b/src/Polly/AsyncPolicy.Implementation.cs similarity index 59% rename from src/Polly/AsyncPolicy.NonGenericImplementation.cs rename to src/Polly/AsyncPolicy.Implementation.cs index 8c856542682..bb4bc4087f7 100644 --- a/src/Polly/AsyncPolicy.NonGenericImplementation.cs +++ b/src/Polly/AsyncPolicy.Implementation.cs @@ -1,46 +1,45 @@ -using System; -using System.Threading; +using System.Threading; using System.Threading.Tasks; -using Polly.Utilities; namespace Polly { + /// + /// Transient exception handling policies that can be applied to asynchronous delegates + /// public abstract partial class AsyncPolicy { /// - /// Defines the implementation of a policy for async executions with no return value. + /// Defines the implementation of a policy for sync executions with no return value. /// /// The action passed by calling code to execute through the policy. /// The policy execution context. /// A token to signal that execution should be cancelled. /// Whether async continuations should continue on a captured context. - /// A representing the result of the execution. - protected virtual Task ImplementationAsync( - Func action, + /// A representing the execution. + protected virtual Task AsyncNonGenericImplementation( + in TExecutableAsync action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) - => ImplementationAsync(async (ctx, token) => - { - await action(ctx, token).ConfigureAwait(continueOnCapturedContext); - return EmptyStruct.Instance; - }, context, cancellationToken, continueOnCapturedContext); + where TExecutableAsync : IAsyncExecutable + { + return AsyncGenericImplementation(action, context, cancellationToken, continueOnCapturedContext); + } + /// /// Defines the implementation of a policy for async executions returning . /// - /// The type returned by asynchronous executions through the implementation. /// The action passed by calling code to execute through the policy. /// The policy execution context. /// A token to signal that execution should be cancelled. /// Whether async continuations should continue on a captured context. - /// A representing the result of the execution. - protected abstract Task ImplementationAsync( - Func> action, + /// A representing the result of the execution. + protected abstract Task AsyncGenericImplementation( + TExecutableAsync action, Context context, CancellationToken cancellationToken, - bool continueOnCapturedContext - ); - + bool continueOnCapturedContext) + where TExecutableAsync : IAsyncExecutable; } } diff --git a/src/Polly/AsyncPolicy.ContextAndKeys.cs b/src/Polly/AsyncPolicy.PolicyKeys.cs similarity index 100% rename from src/Polly/AsyncPolicy.ContextAndKeys.cs rename to src/Polly/AsyncPolicy.PolicyKeys.cs diff --git a/src/Polly/AsyncPolicy.TResult.ExecuteOverloads.cs b/src/Polly/AsyncPolicy.TResult.ExecuteOverloads.cs deleted file mode 100644 index 814e17b6537..00000000000 --- a/src/Polly/AsyncPolicy.TResult.ExecuteOverloads.cs +++ /dev/null @@ -1,252 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Threading; -using System.Threading.Tasks; - -namespace Polly -{ - public abstract partial class AsyncPolicy : IAsyncPolicy - { - - #region ExecuteAsync overloads - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The action to perform. - /// The value returned by the action - [DebuggerStepThrough] - public Task ExecuteAsync(Func> action) - => ExecuteAsync((ctx, ct) => action(), new Context(), CancellationToken.None, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - /// The value returned by the action - [DebuggerStepThrough] - public Task ExecuteAsync(Func> action, IDictionary contextData) - => ExecuteAsync((ctx, ct) => action(ctx), new Context(contextData), CancellationToken.None, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The action to perform. - /// Context data that is passed to the exception policy. - /// The value returned by the action - [DebuggerStepThrough] - public Task ExecuteAsync(Func> action, Context context) - => ExecuteAsync((ctx, ct) => action(ctx), context, CancellationToken.None, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The action to perform. - /// A cancellation token which can be used to cancel the action. When a retry policy is in use, also cancels any further retries. - /// The value returned by the action - [DebuggerStepThrough] - public Task ExecuteAsync(Func> action, CancellationToken cancellationToken) - => ExecuteAsync((ctx, ct) => action(ct), new Context(), cancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The action to perform. - /// Whether to continue on a captured synchronization context. - /// A cancellation token which can be used to cancel the action. When a retry policy is in use, also cancels any further retries. - /// The value returned by the action - /// Please use asynchronous-defined policies when calling asynchronous ExecuteAsync (and similar) methods. - [DebuggerStepThrough] - public Task ExecuteAsync(Func> action, CancellationToken cancellationToken, bool continueOnCapturedContext) - => ExecuteAsync((ctx, ct) => action(ct), new Context(), cancellationToken, continueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - /// The value returned by the action - [DebuggerStepThrough] - public Task ExecuteAsync(Func> action, IDictionary contextData, CancellationToken cancellationToken) - => ExecuteAsync(action, new Context(contextData), cancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The action to perform. - /// Context data that is passed to the exception policy. - /// A cancellation token which can be used to cancel the action. When a retry policy is in use, also cancels any further retries. - /// The value returned by the action - [DebuggerStepThrough] - public Task ExecuteAsync(Func> action, Context context, CancellationToken cancellationToken) - => ExecuteAsync(action, context, cancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - /// Whether to continue on a captured synchronization context. - /// The value returned by the action - /// contextData - [DebuggerStepThrough] - public Task ExecuteAsync(Func> action, IDictionary contextData, CancellationToken cancellationToken, bool continueOnCapturedContext) - => ExecuteAsync(action, new Context(contextData), cancellationToken, continueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The action to perform. - /// Context data that is passed to the exception policy. - /// Whether to continue on a captured synchronization context. - /// A cancellation token which can be used to cancel the action. When a retry policy is in use, also cancels any further retries. - /// The value returned by the action - /// Please use asynchronous-defined policies when calling asynchronous ExecuteAsync (and similar) methods. - [DebuggerStepThrough] - public async Task ExecuteAsync(Func> action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) - { - if (context == null) throw new ArgumentNullException(nameof(context)); - - SetPolicyContext(context, out string priorPolicyWrapKey, out string priorPolicyKey); - - try - { - return await ImplementationAsync(action, context, cancellationToken, continueOnCapturedContext).ConfigureAwait(continueOnCapturedContext); - } - finally - { - RestorePolicyContext(context, priorPolicyWrapKey, priorPolicyKey); - } - } - - #endregion - - #region ExecuteAndCaptureAsync overloads - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The action to perform. - /// The captured result - [DebuggerStepThrough] - public Task> ExecuteAndCaptureAsync(Func> action) - => ExecuteAndCaptureAsync((ctx, ct) => action(), new Context(), CancellationToken.None, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - /// contextData - /// The captured result - [DebuggerStepThrough] - public Task> ExecuteAndCaptureAsync(Func> action, IDictionary contextData) - => ExecuteAndCaptureAsync((ctx, ct) => action(ctx), new Context(contextData), CancellationToken.None, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The action to perform. - /// Context data that is passed to the exception policy. - /// The captured result - [DebuggerStepThrough] - public Task> ExecuteAndCaptureAsync(Func> action, Context context) - => ExecuteAndCaptureAsync((ctx, ct) => action(ctx), context, CancellationToken.None, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The action to perform. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - /// The captured result - [DebuggerStepThrough] - public Task> ExecuteAndCaptureAsync(Func> action, CancellationToken cancellationToken) - => ExecuteAndCaptureAsync((ctx, ct) => action(ct), new Context(), cancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The action to perform. - /// Whether to continue on a captured synchronization context. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - /// The captured result - /// Please use asynchronous-defined policies when calling asynchronous ExecuteAsync (and similar) methods. - [DebuggerStepThrough] - public Task> ExecuteAndCaptureAsync(Func> action, CancellationToken cancellationToken, bool continueOnCapturedContext) - => ExecuteAndCaptureAsync((ctx, ct) => action(ct), new Context(), cancellationToken, continueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - /// contextData - /// The captured result - [DebuggerStepThrough] - public Task> ExecuteAndCaptureAsync(Func> action, IDictionary contextData, CancellationToken cancellationToken) - => ExecuteAndCaptureAsync(action, new Context(contextData), cancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The action to perform. - /// Context data that is passed to the exception policy. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - /// The captured result - [DebuggerStepThrough] - public Task> ExecuteAndCaptureAsync(Func> action, Context context, CancellationToken cancellationToken) - => ExecuteAndCaptureAsync(action, context, cancellationToken, DefaultContinueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - /// Whether to continue on a captured synchronization context. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - /// The captured result - /// contextData - [DebuggerStepThrough] - public Task> ExecuteAndCaptureAsync(Func> action, IDictionary contextData, CancellationToken cancellationToken, bool continueOnCapturedContext) - => ExecuteAndCaptureAsync(action, new Context(contextData), cancellationToken, continueOnCapturedContext); - - /// - /// Executes the specified asynchronous action within the policy and returns the result. - /// - /// The action to perform. - /// Context data that is passed to the exception policy. - /// Whether to continue on a captured synchronization context. - /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. - /// The captured result - /// Please use asynchronous-defined policies when calling asynchronous ExecuteAsync (and similar) methods. - [DebuggerStepThrough] - public async Task> ExecuteAndCaptureAsync(Func> action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) - { - if (context == null) throw new ArgumentNullException(nameof(context)); - - try - { - TResult result = await ExecuteAsync(action, context, cancellationToken, continueOnCapturedContext).ConfigureAwait(continueOnCapturedContext); - - if (ResultPredicates.AnyMatch(result)) - { - return PolicyResult.Failure(result, context); - } - - return PolicyResult.Successful(result, context); - } - catch (Exception exception) - { - return PolicyResult.Failure(exception, GetExceptionType(ExceptionPredicates, exception), context); - } - } - - #endregion - - } -} diff --git a/src/Polly/AsyncPolicy.TResult.IAsyncPolicy.cs b/src/Polly/AsyncPolicy.TResult.IAsyncPolicy.cs new file mode 100644 index 00000000000..9d95a6e38e2 --- /dev/null +++ b/src/Polly/AsyncPolicy.TResult.IAsyncPolicy.cs @@ -0,0 +1,411 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; + +namespace Polly +{ + public abstract partial class AsyncPolicy : IAsyncPolicy + { + #region ExecuteAsync overloads + + /// + /// Executes the specified asynchronous function within the policy and returns the result. + /// + /// The function to invoke. + /// The value returned by the function + [DebuggerStepThrough] + public Task ExecuteAsync(Func> func) + { + return ((IAsyncPolicyInternal)this).ExecuteAsync( + new AsyncExecutableFuncNoParams(func), + GetDefaultExecutionContext(), + DefaultCancellationToken, + DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous function within the policy and returns the result. + /// + /// The function to invoke. + /// Arbitrary data that is passed to the exception policy. + /// The value returned by the function + [DebuggerStepThrough] + public Task ExecuteAsync(Func> func, IDictionary contextData) + { + return ((IAsyncPolicyInternal)this).ExecuteAsync( + new AsyncExecutableFuncOnContext(func), + new Context(contextData), + DefaultCancellationToken, + DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous function within the policy and returns the result. + /// + /// The function to invoke. + /// Context data that is passed to the exception policy. + /// The value returned by the function + [DebuggerStepThrough] + public Task ExecuteAsync(Func> func, Context context) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAsync( + new AsyncExecutableFuncOnContext(func), + context, + DefaultCancellationToken, + DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous function within the policy and returns the result. + /// + /// The function to invoke. + /// A cancellation token which can be used to cancel the action. When a retry policy is in use, also cancels any further retries. + /// The value returned by the function + [DebuggerStepThrough] + public Task ExecuteAsync(Func> func, CancellationToken cancellationToken) + { + return ((IAsyncPolicyInternal)this).ExecuteAsync( + new AsyncExecutableFuncOnCancellationToken(func), + GetDefaultExecutionContext(), + cancellationToken, + DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous function within the policy and returns the result. + /// + /// The function to invoke. + /// Arbitrary data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value returned by the function + [DebuggerStepThrough] + public Task ExecuteAsync(Func> func, IDictionary contextData, CancellationToken cancellationToken) + { + return ((IAsyncPolicyInternal)this).ExecuteAsync( + new AsyncExecutableFuncOnContextCancellationToken(func), + new Context(contextData), + cancellationToken, + DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous function within the policy and returns the result. + /// + /// The function to invoke. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy is in use, also cancels any further retries. + /// The value returned by the function + [DebuggerStepThrough] + public Task ExecuteAsync(Func> func, Context context, CancellationToken cancellationToken) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAsync( + new AsyncExecutableFuncOnContextCancellationToken(func), + context, + cancellationToken, + DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous function within the policy and returns the result. + /// + /// The function to invoke. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy is in use, also cancels any further retries. + /// The value returned by the function + [DebuggerStepThrough] + public Task ExecuteAsync(Func> func, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + return ((IAsyncPolicyInternal)this).ExecuteAsync( + new AsyncExecutableFuncOnCancellationToken(func), + GetDefaultExecutionContext(), + cancellationToken, + continueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous function within the policy and returns the result. + /// + /// The function to invoke. + /// Arbitrary data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// Whether to continue on a captured synchronization context. + /// The value returned by the function + /// contextData + [DebuggerStepThrough] + public Task ExecuteAsync(Func> func, IDictionary contextData, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + return ((IAsyncPolicyInternal)this).ExecuteAsync( + new AsyncExecutableFuncOnContextCancellationToken(func), + new Context(contextData), + cancellationToken, + continueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous function within the policy and returns the result. + /// + /// The function to execute. + /// Context data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy is in use, also cancels any further retries. + /// The value returned by the function + [DebuggerStepThrough] + public Task ExecuteAsync(Func> func, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAsync( + new AsyncExecutableFuncOnContextCancellationToken(func), + context, + cancellationToken, + continueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous function within the policy, passing an extra input of user-defined type , and returns the result. + /// + /// The function to execute. + /// Context data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The type of the first custom input to the function. + /// The value returned by the function + [DebuggerStepThrough] + public Task ExecuteAsync(Func> func, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, T1 input1) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAsync(new AsyncExecutableFunc(func, input1), context, cancellationToken, continueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous function within the policy, passing two extra inputs of user-defined types and , and returns the result. + /// + /// The function to execute. + /// Context data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The value of the second custom input to the function. + /// The type of the first custom input to the function. + /// The type of the second custom input to the function. + /// The value returned by the function + [DebuggerStepThrough] + public Task ExecuteAsync(Func> func, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, T1 input1, T2 input2) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAsync(new AsyncExecutableFunc(func, input1, input2), context, cancellationToken, continueOnCapturedContext); + } + + #endregion + + #region ExecuteAndCaptureAsync overloads + + /// + /// Executes the specified asynchronous action within the policy and returns the result. + /// + /// The function to invoke. + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task> ExecuteAndCaptureAsync(Func> func) + { + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync( + new AsyncExecutableFuncNoParams(func), + GetDefaultExecutionContext(), + DefaultCancellationToken, + DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy and returns the result. + /// + /// The function to invoke. + /// Arbitrary data that is passed to the exception policy. + /// contextData + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task> ExecuteAndCaptureAsync(Func> func, IDictionary contextData) + { + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync( + new AsyncExecutableFuncOnContext(func), + new Context(contextData), + DefaultCancellationToken, + DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy and returns the result. + /// + /// The function to invoke. + /// Context data that is passed to the exception policy. + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task> ExecuteAndCaptureAsync(Func> func, Context context) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync( + new AsyncExecutableFuncOnContext(func), + context, + DefaultCancellationToken, + DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy and returns the result. + /// + /// The function to invoke. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task> ExecuteAndCaptureAsync(Func> func, CancellationToken cancellationToken) + { + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync( + new AsyncExecutableFuncOnCancellationToken(func), + GetDefaultExecutionContext(), + cancellationToken, + DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy and returns the result. + /// + /// The function to invoke. + /// Arbitrary data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// contextData + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task> ExecuteAndCaptureAsync(Func> func, IDictionary contextData, CancellationToken cancellationToken) + { + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync( + new AsyncExecutableFuncOnContextCancellationToken(func), + new Context(contextData), + cancellationToken, + DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy and returns the result. + /// + /// The function to invoke. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task> ExecuteAndCaptureAsync(Func> func, Context context, CancellationToken cancellationToken) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync( + new AsyncExecutableFuncOnContextCancellationToken(func), + context, + cancellationToken, + DefaultContinueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy and returns the result. + /// + /// The function to invoke. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// Whether to continue on a captured synchronization context. + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task> ExecuteAndCaptureAsync(Func> func, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync( + new AsyncExecutableFuncOnCancellationToken(func), + GetDefaultExecutionContext(), + cancellationToken, + continueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy and returns the result. + /// + /// The function to invoke. + /// Arbitrary data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The outcome of the execution, as a promise of a captured + /// contextData + [DebuggerStepThrough] + public Task> ExecuteAndCaptureAsync(Func> func, IDictionary contextData, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync( + new AsyncExecutableFuncOnContextCancellationToken(func), + new Context(contextData), + cancellationToken, + continueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous action within the policy and returns the result. + /// + /// The function to invoke. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// Whether to continue on a captured synchronization context. + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task> ExecuteAndCaptureAsync(Func> func, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync( + new AsyncExecutableFuncOnContextCancellationToken(func), + context, + cancellationToken, + continueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous function within the policy, passing an extra input of user-defined type , and returns the captured result. + /// + /// The function to execute. + /// Context data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The type of the first custom input to the function. + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task> ExecuteAndCaptureAsync(Func> func, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, T1 input1) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync(new AsyncExecutableFunc(func, input1), context, cancellationToken, continueOnCapturedContext); + } + + /// + /// Executes the specified asynchronous function within the policy, passing two extra inputs of user-defined types and , and returns the result. + /// + /// The function to execute. + /// Context data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The value of the second custom input to the function. + /// The type of the first custom input to the function. + /// The type of the second custom input to the function. + /// The outcome of the execution, as a promise of a captured + [DebuggerStepThrough] + public Task> ExecuteAndCaptureAsync(Func> func, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, T1 input1, T2 input2) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((IAsyncPolicyInternal)this).ExecuteAndCaptureAsync(new AsyncExecutableFunc(func, input1, input2), context, cancellationToken, continueOnCapturedContext); + } + + #endregion + } +} diff --git a/src/Polly/AsyncPolicy.TResult.IAsyncPolicyInternal.cs b/src/Polly/AsyncPolicy.TResult.IAsyncPolicyInternal.cs new file mode 100644 index 00000000000..94f8ddbd112 --- /dev/null +++ b/src/Polly/AsyncPolicy.TResult.IAsyncPolicyInternal.cs @@ -0,0 +1,50 @@ +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; + +namespace Polly +{ + public abstract partial class AsyncPolicy : IAsyncPolicyInternal + { + [DebuggerStepThrough] + async Task IAsyncPolicyInternal.ExecuteAsync(TExecutableAsync action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + SetPolicyContext(context, out string priorPolicyWrapKey, out string priorPolicyKey); + + try + { + return await AsyncGenericImplementation(action, context, cancellationToken, continueOnCapturedContext) + .ConfigureAwait(continueOnCapturedContext); + } + finally + { + RestorePolicyContext(context, priorPolicyWrapKey, priorPolicyKey); + } + } + + [DebuggerStepThrough] + async Task> IAsyncPolicyInternal.ExecuteAndCaptureAsync(TExecutableAsync action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + try + { + TResult result = await ((IAsyncPolicyInternal)this).ExecuteAsync(action, context, cancellationToken, continueOnCapturedContext).ConfigureAwait(continueOnCapturedContext); + + if (ResultPredicates.AnyMatch(result)) + { + return PolicyResult.Failure(result, context); + } + + return PolicyResult.Successful(result, context); + } + catch (Exception exception) + { + return PolicyResult.Failure(exception, GetExceptionType(ExceptionPredicates, exception), context); + } + } + } +} diff --git a/src/Polly/AsyncPolicy.GenericImplementation.cs b/src/Polly/AsyncPolicy.TResult.Implementation.cs similarity index 61% rename from src/Polly/AsyncPolicy.GenericImplementation.cs rename to src/Polly/AsyncPolicy.TResult.Implementation.cs index 85b0d27d92b..8023da6cd7d 100644 --- a/src/Polly/AsyncPolicy.GenericImplementation.cs +++ b/src/Polly/AsyncPolicy.TResult.Implementation.cs @@ -1,9 +1,11 @@ -using System; -using System.Threading; +using System.Threading; using System.Threading.Tasks; namespace Polly { + /// + /// Transient exception handling policies that can be applied to asynchronous delegates + /// public abstract partial class AsyncPolicy { /// @@ -13,12 +15,12 @@ public abstract partial class AsyncPolicy /// The policy execution context. /// A token to signal that execution should be cancelled. /// Whether async continuations should continue on a captured context. - /// A representing the result of the execution. - protected abstract Task ImplementationAsync( - Func> action, + /// A representing the result of the execution. + protected abstract Task AsyncGenericImplementation( + TExecutableAsync action, Context context, CancellationToken cancellationToken, - bool continueOnCapturedContext - ); + bool continueOnCapturedContext) + where TExecutableAsync : IAsyncExecutable; } -} +} \ No newline at end of file diff --git a/src/Polly/AsyncPolicy.TResult.cs b/src/Polly/AsyncPolicy.TResult.cs index 684b7d19452..08e4720d134 100644 --- a/src/Polly/AsyncPolicy.TResult.cs +++ b/src/Polly/AsyncPolicy.TResult.cs @@ -27,4 +27,4 @@ protected AsyncPolicy(PolicyBuilder policyBuilder = null) { } } -} +} \ No newline at end of file diff --git a/src/Polly/AsyncPolicy.cs b/src/Polly/AsyncPolicy.cs index e4ab8f73e3c..88d4eb87390 100644 --- a/src/Polly/AsyncPolicy.cs +++ b/src/Polly/AsyncPolicy.cs @@ -3,7 +3,7 @@ /// /// Transient exception handling policies that can be applied to asynchronous delegates /// - public abstract partial class AsyncPolicy + public abstract partial class AsyncPolicy : PolicyBase { /// /// Constructs a new instance of a derived type with the passed . @@ -23,4 +23,4 @@ protected AsyncPolicy(PolicyBuilder policyBuilder = null) { } } -} +} \ No newline at end of file diff --git a/src/Polly/Bulkhead/AsyncBulkheadEngine.cs b/src/Polly/Bulkhead/AsyncBulkheadEngine.cs index 6715dd464d4..64c739d3c33 100644 --- a/src/Polly/Bulkhead/AsyncBulkheadEngine.cs +++ b/src/Polly/Bulkhead/AsyncBulkheadEngine.cs @@ -6,14 +6,15 @@ namespace Polly.Bulkhead { internal static class AsyncBulkheadEngine { - internal static async Task ImplementationAsync( - Func> action, + internal static async Task ImplementationAsync( + TExecutableAsync action, Context context, Func onBulkheadRejectedAsync, SemaphoreSlim maxParallelizationSemaphore, SemaphoreSlim maxQueuedActionsSemaphore, CancellationToken cancellationToken, bool continueOnCapturedContext) + where TExecutableAsync : IAsyncExecutable { if (!await maxQueuedActionsSemaphore.WaitAsync(TimeSpan.Zero, cancellationToken).ConfigureAwait(continueOnCapturedContext)) { @@ -26,7 +27,7 @@ internal static async Task ImplementationAsync( try { - return await action(context, cancellationToken).ConfigureAwait(continueOnCapturedContext); + return await action.ExecuteAsync(context, cancellationToken, continueOnCapturedContext).ConfigureAwait(continueOnCapturedContext); } finally { diff --git a/src/Polly/Bulkhead/AsyncBulkheadPolicy.cs b/src/Polly/Bulkhead/AsyncBulkheadPolicy.cs index dc6ccbc6654..804f13ae7c5 100644 --- a/src/Polly/Bulkhead/AsyncBulkheadPolicy.cs +++ b/src/Polly/Bulkhead/AsyncBulkheadPolicy.cs @@ -13,7 +13,7 @@ public class AsyncBulkheadPolicy : AsyncPolicy, IAsyncBulkheadPolicy private readonly SemaphoreSlim _maxParallelizationSemaphore; private readonly SemaphoreSlim _maxQueuedActionsSemaphore; private readonly int _maxQueueingActions; - private Func _onBulkheadRejectedAsync; + private readonly Func _onBulkheadRejectedAsync; internal AsyncBulkheadPolicy( int maxParallelization, @@ -38,10 +38,10 @@ internal AsyncBulkheadPolicy( /// [DebuggerStepThrough] - protected override Task ImplementationAsync(Func> action, Context context, CancellationToken cancellationToken, - bool continueOnCapturedContext) + protected override Task AsyncGenericImplementation(TExecutableAsync action, Context context, + CancellationToken cancellationToken, bool continueOnCapturedContext) { - return AsyncBulkheadEngine.ImplementationAsync(action, context, _onBulkheadRejectedAsync, _maxParallelizationSemaphore, _maxQueuedActionsSemaphore, cancellationToken, continueOnCapturedContext); + return AsyncBulkheadEngine.ImplementationAsync(action, context, _onBulkheadRejectedAsync, _maxParallelizationSemaphore, _maxQueuedActionsSemaphore, cancellationToken, continueOnCapturedContext); } /// @@ -61,7 +61,7 @@ public class AsyncBulkheadPolicy : AsyncPolicy, IAsyncBulkhead private readonly SemaphoreSlim _maxParallelizationSemaphore; private readonly SemaphoreSlim _maxQueuedActionsSemaphore; private readonly int _maxQueueingActions; - private Func _onBulkheadRejectedAsync; + private readonly Func _onBulkheadRejectedAsync; internal AsyncBulkheadPolicy( int maxParallelization, @@ -76,9 +76,10 @@ internal AsyncBulkheadPolicy( /// [DebuggerStepThrough] - protected override Task ImplementationAsync(Func> action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) + protected override Task AsyncGenericImplementation(TExecutableAsync action, Context context, + CancellationToken cancellationToken, bool continueOnCapturedContext) { - return AsyncBulkheadEngine.ImplementationAsync(action, context, _onBulkheadRejectedAsync, _maxParallelizationSemaphore, _maxQueuedActionsSemaphore, cancellationToken, continueOnCapturedContext); + return AsyncBulkheadEngine.ImplementationAsync(action, context, _onBulkheadRejectedAsync, _maxParallelizationSemaphore, _maxQueuedActionsSemaphore, cancellationToken, continueOnCapturedContext); } /// diff --git a/src/Polly/Bulkhead/AsyncBulkheadTResultSyntax.cs b/src/Polly/Bulkhead/AsyncBulkheadTResultSyntax.cs index 8365a2c0d7e..5aa67ed962c 100644 --- a/src/Polly/Bulkhead/AsyncBulkheadTResultSyntax.cs +++ b/src/Polly/Bulkhead/AsyncBulkheadTResultSyntax.cs @@ -1,5 +1,4 @@ using Polly.Bulkhead; -using Polly.Utilities; using System; using System.Threading.Tasks; @@ -15,8 +14,7 @@ public partial class Policy /// The policy instance. public static IAsyncBulkheadPolicy BulkheadAsync(int maxParallelization) { - Func doNothingAsync = _ => TaskHelper.EmptyTask; - return BulkheadAsync(maxParallelization, 0, doNothingAsync); + return BulkheadAsync(maxParallelization, maxQueuingActions: 0, onBulkheadRejectedAsync: null); } /// @@ -29,7 +27,7 @@ public static IAsyncBulkheadPolicy BulkheadAsync(int maxParall /// The policy instance. public static IAsyncBulkheadPolicy BulkheadAsync(int maxParallelization, Func onBulkheadRejectedAsync) - => BulkheadAsync(maxParallelization, 0, onBulkheadRejectedAsync); + => BulkheadAsync(maxParallelization, maxQueuingActions: 0, onBulkheadRejectedAsync); /// /// Builds a bulkhead isolation , which limits the maximum concurrency of actions executed through the policy. Imposing a maximum concurrency limits the potential of governed actions, when faulting, to bring down the system. @@ -42,8 +40,7 @@ public static IAsyncBulkheadPolicy BulkheadAsync(int maxParall /// maxQueuingActions;Value must be greater than or equal to zero. public static IAsyncBulkheadPolicy BulkheadAsync(int maxParallelization, int maxQueuingActions) { - Func doNothingAsync = _ => TaskHelper.EmptyTask; - return BulkheadAsync(maxParallelization, maxQueuingActions, doNothingAsync); + return BulkheadAsync(maxParallelization, maxQueuingActions, onBulkheadRejectedAsync: null); } /// diff --git a/src/Polly/Bulkhead/BulkheadEngine.cs b/src/Polly/Bulkhead/BulkheadEngine.cs index f5137b6c532..5170a3c9b8e 100644 --- a/src/Polly/Bulkhead/BulkheadEngine.cs +++ b/src/Polly/Bulkhead/BulkheadEngine.cs @@ -5,13 +5,14 @@ namespace Polly.Bulkhead { internal static class BulkheadEngine { - internal static TResult Implementation( - Func action, + internal static TResult Implementation( + in TExecutable action, Context context, Action onBulkheadRejected, SemaphoreSlim maxParallelizationSemaphore, SemaphoreSlim maxQueuedActionsSemaphore, CancellationToken cancellationToken) + where TExecutable : ISyncExecutable { if (!maxQueuedActionsSemaphore.Wait(TimeSpan.Zero, cancellationToken)) { @@ -24,7 +25,7 @@ internal static TResult Implementation( maxParallelizationSemaphore.Wait(cancellationToken); try { - return action(context, cancellationToken); + return action.Execute(context, cancellationToken); } finally { diff --git a/src/Polly/Bulkhead/BulkheadPolicy.cs b/src/Polly/Bulkhead/BulkheadPolicy.cs index db6f2d7b36e..c03d92477a6 100644 --- a/src/Polly/Bulkhead/BulkheadPolicy.cs +++ b/src/Polly/Bulkhead/BulkheadPolicy.cs @@ -27,8 +27,9 @@ internal BulkheadPolicy( /// [DebuggerStepThrough] - protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken) - => BulkheadEngine.Implementation(action, context, _onBulkheadRejected, _maxParallelizationSemaphore, _maxQueuedActionsSemaphore, cancellationToken); + protected override TResult SyncGenericImplementation(in TExecutable action, Context context, + CancellationToken cancellationToken) + => BulkheadEngine.Implementation(action, context, _onBulkheadRejected, _maxParallelizationSemaphore, _maxQueuedActionsSemaphore, cancellationToken); /// /// Gets the number of slots currently available for executing actions through the bulkhead. @@ -76,8 +77,8 @@ internal BulkheadPolicy( /// [DebuggerStepThrough] - protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken) - => BulkheadEngine.Implementation(action, context, _onBulkheadRejected, _maxParallelizationSemaphore, _maxQueuedActionsSemaphore, cancellationToken); + protected override TResult SyncGenericImplementation(in TExecutable action, Context context, CancellationToken cancellationToken) + => BulkheadEngine.Implementation(action, context, _onBulkheadRejected, _maxParallelizationSemaphore, _maxQueuedActionsSemaphore, cancellationToken); /// /// Gets the number of slots currently available for executing actions through the bulkhead. diff --git a/src/Polly/Caching/AsyncCacheEngine.cs b/src/Polly/Caching/AsyncCacheEngine.cs index c39aa36440c..2e8ec896700 100644 --- a/src/Polly/Caching/AsyncCacheEngine.cs +++ b/src/Polly/Caching/AsyncCacheEngine.cs @@ -6,11 +6,11 @@ namespace Polly.Caching { internal static class AsyncCacheEngine { - internal static async Task ImplementationAsync( + internal static async Task ImplementationAsync( IAsyncCacheProvider cacheProvider, ITtlStrategy ttlStrategy, Func cacheKeyStrategy, - Func> action, + TExecutableAsync action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, @@ -19,13 +19,14 @@ internal static async Task ImplementationAsync( Action onCachePut, Action onCacheGetError, Action onCachePutError) + where TExecutableAsync : IAsyncExecutable { cancellationToken.ThrowIfCancellationRequested(); string cacheKey = cacheKeyStrategy(context); if (cacheKey == null) { - return await action(context, cancellationToken).ConfigureAwait(continueOnCapturedContext); + return await action.ExecuteAsync(context, cancellationToken, continueOnCapturedContext).ConfigureAwait(continueOnCapturedContext); } bool cacheHit; @@ -50,7 +51,7 @@ internal static async Task ImplementationAsync( onCacheMiss?.Invoke(context, cacheKey); } - TResult result = await action(context, cancellationToken).ConfigureAwait(continueOnCapturedContext); + TResult result = await action.ExecuteAsync(context, cancellationToken, continueOnCapturedContext).ConfigureAwait(continueOnCapturedContext); Ttl ttl = ttlStrategy.GetTtl(context, result); if (ttl.Timespan > TimeSpan.Zero) diff --git a/src/Polly/Caching/AsyncCachePolicy.cs b/src/Polly/Caching/AsyncCachePolicy.cs index 4ac3ea1cb01..e86f0d7948b 100644 --- a/src/Polly/Caching/AsyncCachePolicy.cs +++ b/src/Polly/Caching/AsyncCachePolicy.cs @@ -42,32 +42,28 @@ internal AsyncCachePolicy( } /// - protected override Task ImplementationAsync( - Func action, - Context context, - CancellationToken cancellationToken, + protected override Task AsyncNonGenericImplementation(in TExecutableAsync action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) { // Pass-through/NOOP policy action, for void-returning executions through the cache policy. - return action(context, cancellationToken); + return action.ExecuteAsync(context, cancellationToken, continueOnCapturedContext); } /// [DebuggerStepThrough] - protected override Task ImplementationAsync(Func> action, Context context, CancellationToken cancellationToken, - bool continueOnCapturedContext) + protected override Task AsyncGenericImplementation(TExecutableAsync action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) { - return AsyncCacheEngine.ImplementationAsync( - _asyncCacheProvider.AsyncFor(), - _ttlStrategy.For(), - _cacheKeyStrategy, - action, - context, + return AsyncCacheEngine.ImplementationAsync( + _asyncCacheProvider.AsyncFor(), + _ttlStrategy.For(), + _cacheKeyStrategy, + action, + context, cancellationToken, - continueOnCapturedContext, - _onCacheGet, - _onCacheMiss, - _onCachePut, + continueOnCapturedContext, + _onCacheGet, + _onCacheMiss, + _onCachePut, _onCacheGetError, _onCachePutError); } @@ -79,7 +75,7 @@ protected override Task ImplementationAsync(FuncThe return type of delegates which may be executed through the policy. public class AsyncCachePolicy : AsyncPolicy, IAsyncCachePolicy { - private IAsyncCacheProvider _asyncCacheProvider; + private readonly IAsyncCacheProvider _asyncCacheProvider; private readonly ITtlStrategy _ttlStrategy; private readonly Func _cacheKeyStrategy; @@ -112,10 +108,9 @@ internal AsyncCachePolicy( /// [DebuggerStepThrough] - protected override Task ImplementationAsync(Func> action, Context context, CancellationToken cancellationToken, - bool continueOnCapturedContext) + protected override Task AsyncGenericImplementation(TExecutableAsync action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) { - return AsyncCacheEngine.ImplementationAsync( + return AsyncCacheEngine.ImplementationAsync( _asyncCacheProvider, _ttlStrategy, _cacheKeyStrategy, diff --git a/src/Polly/Caching/CacheEngine.cs b/src/Polly/Caching/CacheEngine.cs index e684ed32574..0bbeff896e4 100644 --- a/src/Polly/Caching/CacheEngine.cs +++ b/src/Polly/Caching/CacheEngine.cs @@ -5,11 +5,11 @@ namespace Polly.Caching { internal static class CacheEngine { - internal static TResult Implementation( + internal static TResult Implementation( ISyncCacheProvider cacheProvider, ITtlStrategy ttlStrategy, Func cacheKeyStrategy, - Func action, + in TExecutable action, Context context, CancellationToken cancellationToken, Action onCacheGet, @@ -17,13 +17,14 @@ internal static TResult Implementation( Action onCachePut, Action onCacheGetError, Action onCachePutError) + where TExecutable : ISyncExecutable { cancellationToken.ThrowIfCancellationRequested(); string cacheKey = cacheKeyStrategy(context); if (cacheKey == null) { - return action(context, cancellationToken); + return action.Execute(context, cancellationToken); } bool cacheHit; @@ -48,7 +49,7 @@ internal static TResult Implementation( onCacheMiss?.Invoke(context, cacheKey); } - TResult result = action(context, cancellationToken); + TResult result = action.Execute(context, cancellationToken); Ttl ttl = ttlStrategy.GetTtl(context, result); if (ttl.Timespan > TimeSpan.Zero) diff --git a/src/Polly/Caching/CachePolicy.cs b/src/Polly/Caching/CachePolicy.cs index f7d9f4644d4..6fcd89827c0 100644 --- a/src/Polly/Caching/CachePolicy.cs +++ b/src/Polly/Caching/CachePolicy.cs @@ -41,15 +41,15 @@ internal CachePolicy( } /// - protected override void Implementation(Action action, Context context, CancellationToken cancellationToken) + protected override void SyncNonGenericImplementation(in TExecutable action, Context context, CancellationToken cancellationToken) // Pass-through/NOOP policy action, for void-returning calls through a cache policy. - => action(context, cancellationToken); + => action.Execute(context, cancellationToken); /// [DebuggerStepThrough] - protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken) + protected override TResult SyncGenericImplementation(in TExecutable action, Context context, CancellationToken cancellationToken) { - return CacheEngine.Implementation( + return CacheEngine.Implementation( _syncCacheProvider.For(), _ttlStrategy.For(), _cacheKeyStrategy, @@ -70,9 +70,9 @@ protected override TResult Implementation(FuncThe return type of delegates which may be executed through the policy. public class CachePolicy : Policy, ISyncCachePolicy { - private ISyncCacheProvider _syncCacheProvider; - private ITtlStrategy _ttlStrategy; - private Func _cacheKeyStrategy; + private readonly ISyncCacheProvider _syncCacheProvider; + private readonly ITtlStrategy _ttlStrategy; + private readonly Func _cacheKeyStrategy; private readonly Action _onCacheGet; private readonly Action _onCacheMiss; @@ -103,7 +103,7 @@ internal CachePolicy( /// [DebuggerStepThrough] - protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken) + protected override TResult SyncGenericImplementation(in TExecutable action, Context context, CancellationToken cancellationToken) => CacheEngine.Implementation( _syncCacheProvider, _ttlStrategy, diff --git a/src/Polly/CircuitBreaker/AdvancedCircuitBreakerSyntax.cs b/src/Polly/CircuitBreaker/AdvancedCircuitBreakerSyntax.cs index 1b8269f1bbc..fa8a816c4c9 100644 --- a/src/Polly/CircuitBreaker/AdvancedCircuitBreakerSyntax.cs +++ b/src/Polly/CircuitBreaker/AdvancedCircuitBreakerSyntax.cs @@ -1,6 +1,5 @@ using System; using Polly.CircuitBreaker; -using Polly.Utilities; namespace Polly { @@ -205,7 +204,7 @@ public static ISyncCircuitBreakerPolicy AdvancedCircuitBreaker(this PolicyBuilde /// (see "Release It!" by Michael T. Nygard fi) public static ISyncCircuitBreakerPolicy AdvancedCircuitBreaker(this PolicyBuilder policyBuilder, double failureThreshold, TimeSpan samplingDuration, int minimumThroughput, TimeSpan durationOfBreak, Action onBreak, Action onReset, Action onHalfOpen) { - var resolutionOfCircuit = TimeSpan.FromTicks(AdvancedCircuitController.ResolutionOfCircuitTimer); + var resolutionOfCircuit = TimeSpan.FromTicks(AdvancedCircuitController.ResolutionOfCircuitTimer); if (failureThreshold <= 0) throw new ArgumentOutOfRangeException(nameof(failureThreshold), "Value must be greater than zero."); if (failureThreshold > 1) throw new ArgumentOutOfRangeException(nameof(failureThreshold), "Value must be less than or equal to one."); @@ -213,12 +212,12 @@ public static ISyncCircuitBreakerPolicy AdvancedCircuitBreaker(this PolicyBuilde if (minimumThroughput <= 1) throw new ArgumentOutOfRangeException(nameof(minimumThroughput), "Value must be greater than one."); if (durationOfBreak < TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(durationOfBreak), "Value must be greater than zero."); - var breakerController = new AdvancedCircuitController( + var breakerController = new AdvancedCircuitController( failureThreshold, samplingDuration, minimumThroughput, durationOfBreak, - onBreak: onBreak == null ? (Action, CircuitState, TimeSpan, Context>)null : (outcome, state, timespan, context) => onBreak(outcome.Exception, state, timespan, context), + onBreak: onBreak == null ? (Action, CircuitState, TimeSpan, Context>)null : (outcome, state, timespan, context) => onBreak(outcome.Exception, state, timespan, context), onReset, onHalfOpen); return new CircuitBreakerPolicy( diff --git a/src/Polly/CircuitBreaker/AdvancedCircuitBreakerTResultSyntax.cs b/src/Polly/CircuitBreaker/AdvancedCircuitBreakerTResultSyntax.cs index 9aefa5ef052..9d56eb128b5 100644 --- a/src/Polly/CircuitBreaker/AdvancedCircuitBreakerTResultSyntax.cs +++ b/src/Polly/CircuitBreaker/AdvancedCircuitBreakerTResultSyntax.cs @@ -1,6 +1,5 @@ using System; using Polly.CircuitBreaker; -using Polly.Utilities; namespace Polly { @@ -207,7 +206,7 @@ public static ISyncCircuitBreakerPolicy AdvancedCircuitBreaker /// (see "Release It!" by Michael T. Nygard fi) public static ISyncCircuitBreakerPolicy AdvancedCircuitBreaker(this PolicyBuilder policyBuilder, double failureThreshold, TimeSpan samplingDuration, int minimumThroughput, TimeSpan durationOfBreak, Action, CircuitState, TimeSpan, Context> onBreak, Action onReset, Action onHalfOpen) { - var resolutionOfCircuit = TimeSpan.FromTicks(AdvancedCircuitController.ResolutionOfCircuitTimer); + var resolutionOfCircuit = TimeSpan.FromTicks(AdvancedCircuitController.ResolutionOfCircuitTimer); if (failureThreshold <= 0) throw new ArgumentOutOfRangeException(nameof(failureThreshold), "Value must be greater than zero."); if (failureThreshold > 1) throw new ArgumentOutOfRangeException(nameof(failureThreshold), "Value must be less than or equal to one."); diff --git a/src/Polly/CircuitBreaker/AsyncAdvancedCircuitBreakerSyntax.cs b/src/Polly/CircuitBreaker/AsyncAdvancedCircuitBreakerSyntax.cs index fc07e518091..e9f856280cc 100644 --- a/src/Polly/CircuitBreaker/AsyncAdvancedCircuitBreakerSyntax.cs +++ b/src/Polly/CircuitBreaker/AsyncAdvancedCircuitBreakerSyntax.cs @@ -1,6 +1,5 @@ using System; using Polly.CircuitBreaker; -using Polly.Utilities; namespace Polly { @@ -210,7 +209,7 @@ public static IAsyncCircuitBreakerPolicy AdvancedCircuitBreakerAsync(this Policy /// durationOfBreak;Value must be greater than zero public static IAsyncCircuitBreakerPolicy AdvancedCircuitBreakerAsync(this PolicyBuilder policyBuilder, double failureThreshold, TimeSpan samplingDuration, int minimumThroughput, TimeSpan durationOfBreak, Action onBreak, Action onReset, Action onHalfOpen) { - var resolutionOfCircuit = TimeSpan.FromTicks(AdvancedCircuitController.ResolutionOfCircuitTimer); + var resolutionOfCircuit = TimeSpan.FromTicks(AdvancedCircuitController.ResolutionOfCircuitTimer); if (failureThreshold <= 0) throw new ArgumentOutOfRangeException(nameof(failureThreshold), "Value must be greater than zero."); if (failureThreshold > 1) throw new ArgumentOutOfRangeException(nameof(failureThreshold), "Value must be less than or equal to one."); @@ -218,12 +217,12 @@ public static IAsyncCircuitBreakerPolicy AdvancedCircuitBreakerAsync(this Policy if (minimumThroughput <= 1) throw new ArgumentOutOfRangeException(nameof(minimumThroughput), "Value must be greater than one."); if (durationOfBreak < TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(durationOfBreak), "Value must be greater than zero."); - var breakerController = new AdvancedCircuitController( + var breakerController = new AdvancedCircuitController( failureThreshold, samplingDuration, minimumThroughput, durationOfBreak, - onBreak: onBreak == null ? (Action, CircuitState, TimeSpan, Context>)null : (outcome, state, timespan, context) => onBreak(outcome.Exception, state, timespan, context), + onBreak: onBreak == null ? (Action, CircuitState, TimeSpan, Context>)null : (outcome, state, timespan, context) => onBreak(outcome.Exception, state, timespan, context), onReset, onHalfOpen); return new AsyncCircuitBreakerPolicy( diff --git a/src/Polly/CircuitBreaker/AsyncAdvancedCircuitBreakerTResultSyntax.cs b/src/Polly/CircuitBreaker/AsyncAdvancedCircuitBreakerTResultSyntax.cs index 3eef344b1de..14601851038 100644 --- a/src/Polly/CircuitBreaker/AsyncAdvancedCircuitBreakerTResultSyntax.cs +++ b/src/Polly/CircuitBreaker/AsyncAdvancedCircuitBreakerTResultSyntax.cs @@ -1,6 +1,5 @@ using System; using Polly.CircuitBreaker; -using Polly.Utilities; namespace Polly { @@ -209,7 +208,7 @@ public static IAsyncCircuitBreakerPolicy AdvancedCircuitBreakerAsyncdurationOfBreak;Value must be greater than zero public static IAsyncCircuitBreakerPolicy AdvancedCircuitBreakerAsync(this PolicyBuilder policyBuilder, double failureThreshold, TimeSpan samplingDuration, int minimumThroughput, TimeSpan durationOfBreak, Action, CircuitState, TimeSpan, Context> onBreak, Action onReset, Action onHalfOpen) { - var resolutionOfCircuit = TimeSpan.FromTicks(AdvancedCircuitController.ResolutionOfCircuitTimer); + var resolutionOfCircuit = TimeSpan.FromTicks(AdvancedCircuitController.ResolutionOfCircuitTimer); if (failureThreshold <= 0) throw new ArgumentOutOfRangeException(nameof(failureThreshold), "Value must be greater than zero."); if (failureThreshold > 1) throw new ArgumentOutOfRangeException(nameof(failureThreshold), "Value must be less than or equal to one."); diff --git a/src/Polly/CircuitBreaker/AsyncCircuitBreakerEngine.cs b/src/Polly/CircuitBreaker/AsyncCircuitBreakerEngine.cs index eadf0f0bd55..5d15edaefa6 100644 --- a/src/Polly/CircuitBreaker/AsyncCircuitBreakerEngine.cs +++ b/src/Polly/CircuitBreaker/AsyncCircuitBreakerEngine.cs @@ -7,14 +7,15 @@ namespace Polly.CircuitBreaker { internal class AsyncCircuitBreakerEngine { - internal static async Task ImplementationAsync( - Func> action, + internal static async Task ImplementationAsync( + TExecutableAsync action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, ExceptionPredicates shouldHandleExceptionPredicates, ResultPredicates shouldHandleResultPredicates, ICircuitController breakerController) + where TExecutableAsync : IAsyncExecutable { cancellationToken.ThrowIfCancellationRequested(); @@ -22,7 +23,7 @@ internal static async Task ImplementationAsync( try { - TResult result = await action(context, cancellationToken).ConfigureAwait(continueOnCapturedContext); + TResult result = await action.ExecuteAsync(context, cancellationToken, continueOnCapturedContext).ConfigureAwait(continueOnCapturedContext); if (shouldHandleResultPredicates.AnyMatch(result)) { diff --git a/src/Polly/CircuitBreaker/AsyncCircuitBreakerPolicy.cs b/src/Polly/CircuitBreaker/AsyncCircuitBreakerPolicy.cs index 35259895b7b..79f8f47cf17 100644 --- a/src/Polly/CircuitBreaker/AsyncCircuitBreakerPolicy.cs +++ b/src/Polly/CircuitBreaker/AsyncCircuitBreakerPolicy.cs @@ -2,7 +2,6 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; -using Polly.Utilities; namespace Polly.CircuitBreaker { @@ -11,11 +10,11 @@ namespace Polly.CircuitBreaker /// public class AsyncCircuitBreakerPolicy : AsyncPolicy, IAsyncCircuitBreakerPolicy { - internal readonly ICircuitController _breakerController; + internal readonly ICircuitController _breakerController; internal AsyncCircuitBreakerPolicy( PolicyBuilder policyBuilder, - ICircuitController breakerController + ICircuitController breakerController ) : base(policyBuilder) { _breakerController = breakerController; @@ -43,18 +42,26 @@ ICircuitController breakerController public void Reset() => _breakerController.Reset(); /// - protected override async Task ImplementationAsync(Func> action, Context context, CancellationToken cancellationToken, + protected override async Task AsyncGenericImplementation(TExecutableAsync action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) { TResult result = default; - await AsyncCircuitBreakerEngine.ImplementationAsync( - async (ctx, ct) => { result = await action(ctx, ct).ConfigureAwait(continueOnCapturedContext); return EmptyStruct.Instance; }, + + // This additional call in is necessary, because _breakerController is generic in . + // We therefore have to convert the whole execution to object. + // It could be removed if ICircuitController was refactored to not be generic in TResult. + // Which could be done by moving onBreak (and similar) out of ICircuitController<>, instead to parameters passed to CircuitBreakerEngine.Implementation<>() (as retry policy does) + // and by removing the LastHandledResult property. + // An allocation is introduced by the closure over action. + await AsyncCircuitBreakerEngine.ImplementationAsync, object>( + new AsyncExecutableAction(async (ctx, ct, cap) => { result = await action.ExecuteAsync(ctx, ct, cap).ConfigureAwait(cap); }), context, cancellationToken, continueOnCapturedContext, ExceptionPredicates, - ResultPredicates.None, + ResultPredicates.None, _breakerController).ConfigureAwait(continueOnCapturedContext); + return result; } } @@ -104,7 +111,7 @@ ICircuitController breakerController /// [DebuggerStepThrough] - protected override Task ImplementationAsync(Func> action, Context context, CancellationToken cancellationToken, + protected override Task AsyncGenericImplementation(TExecutableAsync action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) => AsyncCircuitBreakerEngine.ImplementationAsync( action, diff --git a/src/Polly/CircuitBreaker/AsyncCircuitBreakerSyntax.cs b/src/Polly/CircuitBreaker/AsyncCircuitBreakerSyntax.cs index 238bce7ed99..048c6c1d959 100644 --- a/src/Polly/CircuitBreaker/AsyncCircuitBreakerSyntax.cs +++ b/src/Polly/CircuitBreaker/AsyncCircuitBreakerSyntax.cs @@ -1,6 +1,5 @@ using System; using Polly.CircuitBreaker; -using Polly.Utilities; namespace Polly { @@ -182,10 +181,10 @@ public static IAsyncCircuitBreakerPolicy CircuitBreakerAsync(this PolicyBuilder if (exceptionsAllowedBeforeBreaking <= 0) throw new ArgumentOutOfRangeException(nameof(exceptionsAllowedBeforeBreaking), "Value must be greater than zero."); if (durationOfBreak < TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(durationOfBreak), "Value must be greater than zero."); - var breakerController = new ConsecutiveCountCircuitController( + var breakerController = new ConsecutiveCountCircuitController( exceptionsAllowedBeforeBreaking, durationOfBreak, - onBreak: onBreak == null ? (Action, CircuitState, TimeSpan, Context>)null : (outcome, state, timespan, context) => onBreak(outcome.Exception, state, timespan, context), + onBreak: onBreak == null ? (Action, CircuitState, TimeSpan, Context>)null : (outcome, state, timespan, context) => onBreak(outcome.Exception, state, timespan, context), onReset, onHalfOpen); return new AsyncCircuitBreakerPolicy( diff --git a/src/Polly/CircuitBreaker/CircuitBreakerEngine.cs b/src/Polly/CircuitBreaker/CircuitBreakerEngine.cs index 141eb4167c7..045b023510c 100644 --- a/src/Polly/CircuitBreaker/CircuitBreakerEngine.cs +++ b/src/Polly/CircuitBreaker/CircuitBreakerEngine.cs @@ -6,13 +6,14 @@ namespace Polly.CircuitBreaker { internal class CircuitBreakerEngine { - internal static TResult Implementation( - Func action, + internal static TResult Implementation( + in TExecutable action, Context context, CancellationToken cancellationToken, ExceptionPredicates shouldHandleExceptionPredicates, ResultPredicates shouldHandleResultPredicates, ICircuitController breakerController) + where TExecutable : ISyncExecutable { cancellationToken.ThrowIfCancellationRequested(); @@ -20,7 +21,7 @@ internal static TResult Implementation( try { - TResult result = action(context, cancellationToken); + TResult result = action.Execute(context, cancellationToken); if (shouldHandleResultPredicates.AnyMatch(result)) { diff --git a/src/Polly/CircuitBreaker/CircuitBreakerPolicy.cs b/src/Polly/CircuitBreaker/CircuitBreakerPolicy.cs index 4d4767a78c1..ff4691dc213 100644 --- a/src/Polly/CircuitBreaker/CircuitBreakerPolicy.cs +++ b/src/Polly/CircuitBreaker/CircuitBreakerPolicy.cs @@ -1,6 +1,5 @@ using System; using System.Diagnostics; -using Polly.Utilities; using System.Threading; namespace Polly.CircuitBreaker @@ -10,11 +9,11 @@ namespace Polly.CircuitBreaker /// public class CircuitBreakerPolicy : Policy, ISyncCircuitBreakerPolicy { - internal readonly ICircuitController _breakerController; + internal readonly ICircuitController _breakerController; internal CircuitBreakerPolicy( PolicyBuilder policyBuilder, - ICircuitController breakerController + ICircuitController breakerController ) : base(policyBuilder) => _breakerController = breakerController; @@ -41,15 +40,27 @@ ICircuitController breakerController /// [DebuggerStepThrough] - protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken) + protected override TResult SyncGenericImplementation(in TExecutable action, Context context, + CancellationToken cancellationToken) + => ImplementationSyncInternal(action, context, cancellationToken); + + // This additional private method is necessary, because _breakerController is generic in . + // We therefore have to convert the whole execution to object. + // It could be removed if ICircuitController was refactored to not be generic in TResult. + // Which could be done by moving onBreak (and similar) out of ICircuitController<>, instead to parameters passed to CircuitBreakerEngine.Implementation<>() (as retry policy does) + // and by removing the LastHandledResult property. + // Further, we need to drop the 'in' parameter on TExecutable action, to use action in the lambda. + // An allocation is introduced by the closure over action. + private TResult ImplementationSyncInternal(TExecutable action, Context context, CancellationToken cancellationToken) + where TExecutable : ISyncExecutable { TResult result = default; - CircuitBreakerEngine.Implementation( - (ctx, ct) => { result = action(ctx, ct); return EmptyStruct.Instance; }, + CircuitBreakerEngine.Implementation, object>( + new SyncExecutableAction((ctx, ct) => result = action.Execute(ctx, ct)), context, cancellationToken, ExceptionPredicates, - ResultPredicates.None, + ResultPredicates.None, _breakerController); return result; } @@ -98,7 +109,7 @@ ICircuitController breakerController /// [DebuggerStepThrough] - protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken) + protected override TResult SyncGenericImplementation(in TExecutable action, Context context, CancellationToken cancellationToken) => CircuitBreakerEngine.Implementation( action, context, diff --git a/src/Polly/CircuitBreaker/CircuitBreakerSyntax.cs b/src/Polly/CircuitBreaker/CircuitBreakerSyntax.cs index 53736b707c3..dd3d0e20c70 100644 --- a/src/Polly/CircuitBreaker/CircuitBreakerSyntax.cs +++ b/src/Polly/CircuitBreaker/CircuitBreakerSyntax.cs @@ -1,6 +1,5 @@ using System; using Polly.CircuitBreaker; -using Polly.Utilities; namespace Polly { @@ -181,10 +180,10 @@ public static ISyncCircuitBreakerPolicy CircuitBreaker(this PolicyBuilder policy if (exceptionsAllowedBeforeBreaking <= 0) throw new ArgumentOutOfRangeException(nameof(exceptionsAllowedBeforeBreaking), "Value must be greater than zero."); if (durationOfBreak < TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(durationOfBreak), "Value must be greater than zero."); - var breakerController = new ConsecutiveCountCircuitController( + var breakerController = new ConsecutiveCountCircuitController( exceptionsAllowedBeforeBreaking, durationOfBreak, - onBreak: onBreak == null ? (Action, CircuitState, TimeSpan, Context>)null : (outcome, state, timespan, context) => onBreak(outcome.Exception, state, timespan, context), + onBreak: onBreak == null ? (Action, CircuitState, TimeSpan, Context>)null : (outcome, state, timespan, context) => onBreak(outcome.Exception, state, timespan, context), onReset, onHalfOpen); return new CircuitBreakerPolicy( diff --git a/src/Polly/CircuitBreaker/CircuitStateController.cs b/src/Polly/CircuitBreaker/CircuitStateController.cs index 78f20ecf28a..49920f9906a 100644 --- a/src/Polly/CircuitBreaker/CircuitStateController.cs +++ b/src/Polly/CircuitBreaker/CircuitStateController.cs @@ -59,7 +59,7 @@ public Exception LastException { using (TimedLock.Lock(_lock)) { - return _lastOutcome?.Exception; + return _lastOutcome.Exception; } } } @@ -70,8 +70,7 @@ public TResult LastHandledResult { using (TimedLock.Lock(_lock)) { - return _lastOutcome != null - ? _lastOutcome.Result : default; + return _lastOutcome.Result; } } } @@ -114,7 +113,7 @@ private void BreakFor_NeedsLock(TimeSpan durationOfBreak, Context context) protected void ResetInternal_NeedsLock(Context context) { _blockedTill = DateTime.MinValue.Ticks; - _lastOutcome = null; + _lastOutcome = default; CircuitState priorState = _circuitState; _circuitState = CircuitState.Closed; diff --git a/src/Polly/Context.Dictionary.cs b/src/Polly/Context.Dictionary.cs index 07750752343..26e1eba766c 100644 --- a/src/Polly/Context.Dictionary.cs +++ b/src/Polly/Context.Dictionary.cs @@ -33,7 +33,7 @@ internal Context(IDictionary contextData) : this() wrappedDictionary = new Dictionary(contextData); } -#region IDictionary implementation + #region IDictionary implementation /// public ICollection Keys => WrappedDictionary.Keys; diff --git a/src/Polly/Context.cs b/src/Polly/Context.cs index 9b828c9d029..9fb5d40012b 100644 --- a/src/Polly/Context.cs +++ b/src/Polly/Context.cs @@ -17,7 +17,10 @@ public partial class Context /// Initializes a new instance of the class, with the specified . /// /// The operation key. - public Context(String operationKey) => OperationKey = operationKey; + public Context(String operationKey) : this() + { + OperationKey = operationKey; + } /// /// Initializes a new instance of the class. diff --git a/src/Polly/DelegateResult.cs b/src/Polly/DelegateResult.cs index 5cdee1de360..b25f19f8ba1 100644 --- a/src/Polly/DelegateResult.cs +++ b/src/Polly/DelegateResult.cs @@ -5,19 +5,27 @@ namespace Polly /// /// The captured outcome of executing an individual Func<TResult> /// - public class DelegateResult + public struct DelegateResult { /// /// Create an instance of representing an execution which returned /// /// The result. - public DelegateResult(TResult result) => Result = result; + public DelegateResult(TResult result) + { + Result = result; + Exception = null; + } /// /// Create an instance of representing an execution which threw /// /// The exception. - public DelegateResult(Exception exception) => Exception = exception; + public DelegateResult(Exception exception) + { + Result = default; + Exception = exception; + } /// /// The result of executing the delegate. Will be default(TResult) if an exception was thrown. diff --git a/src/Polly/ExceptionPredicates.cs b/src/Polly/ExceptionPredicates.cs index 2e81b43efec..ba666514f46 100644 --- a/src/Polly/ExceptionPredicates.cs +++ b/src/Polly/ExceptionPredicates.cs @@ -13,7 +13,7 @@ public class ExceptionPredicates internal void Add(ExceptionPredicate predicate) { - _predicates = _predicates ?? new List(); // The ?? pattern here is sufficient; only a deliberately contrived example would lead to the same PolicyBuilder instance being used in a multi-threaded way to define policies simultaneously on multiple threads. + _predicates ??= new List(); // The ?? pattern here is sufficient; only a deliberately contrived example would lead to the same PolicyBuilder instance being used in a multi-threaded way to define policies simultaneously on multiple threads. _predicates.Add(predicate); } diff --git a/src/Polly/Fallback/AsyncFallbackEngine.cs b/src/Polly/Fallback/AsyncFallbackEngine.cs index 5247c86049f..949bc05c02d 100644 --- a/src/Polly/Fallback/AsyncFallbackEngine.cs +++ b/src/Polly/Fallback/AsyncFallbackEngine.cs @@ -6,15 +6,16 @@ namespace Polly.Fallback { internal class AsyncFallbackEngine { - internal static async Task ImplementationAsync( - Func> action, + internal static async Task ImplementationAsync( + TExecutableAsync action, Context context, CancellationToken cancellationToken, + bool continueOnCapturedContext, ExceptionPredicates shouldHandleExceptionPredicates, ResultPredicates shouldHandleResultPredicates, Func, Context, Task> onFallbackAsync, - Func, Context, CancellationToken, Task> fallbackAction, - bool continueOnCapturedContext) + Func, Context, CancellationToken, Task> fallbackAction) + where TExecutableAsync : IAsyncExecutable { DelegateResult delegateOutcome; @@ -22,7 +23,7 @@ internal static async Task ImplementationAsync( { cancellationToken.ThrowIfCancellationRequested(); - TResult result = await action(context, cancellationToken).ConfigureAwait(continueOnCapturedContext); + TResult result = await action.ExecuteAsync(context, cancellationToken, continueOnCapturedContext).ConfigureAwait(continueOnCapturedContext); if (!shouldHandleResultPredicates.AnyMatch(result)) { diff --git a/src/Polly/Fallback/AsyncFallbackPolicy.cs b/src/Polly/Fallback/AsyncFallbackPolicy.cs index 2aa1bc777bc..ef0d9360499 100644 --- a/src/Polly/Fallback/AsyncFallbackPolicy.cs +++ b/src/Polly/Fallback/AsyncFallbackPolicy.cs @@ -2,7 +2,6 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; -using Polly.Utilities; namespace Polly.Fallback { @@ -11,8 +10,8 @@ namespace Polly.Fallback /// public class AsyncFallbackPolicy : AsyncPolicy, IAsyncFallbackPolicy { - private Func _onFallbackAsync; - private Func _fallbackAction; + private readonly Func _onFallbackAsync; + private readonly Func _fallbackAction; internal AsyncFallbackPolicy(PolicyBuilder policyBuilder, Func onFallbackAsync, Func fallbackAction) @@ -23,32 +22,28 @@ internal AsyncFallbackPolicy(PolicyBuilder policyBuilder, Func - protected override Task ImplementationAsync( - Func action, - Context context, - CancellationToken cancellationToken, + protected override Task AsyncNonGenericImplementation(in TExecutableAsync action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) { - return AsyncFallbackEngine.ImplementationAsync( - async (ctx, ct) => { await action(ctx, ct).ConfigureAwait(continueOnCapturedContext); return EmptyStruct.Instance; }, + return AsyncFallbackEngine.ImplementationAsync( + action, context, cancellationToken, + continueOnCapturedContext, ExceptionPredicates, - ResultPredicates.None, - _onFallbackAsync == null ? (Func, Context, Task>)null : (outcome, ctx) => _onFallbackAsync(outcome.Exception, ctx), - async (outcome, ctx, ct) => + ResultPredicates.None, + onFallbackAsync: _onFallbackAsync == null ? (Func, Context, Task>)null : (outcome, ctx) => _onFallbackAsync(outcome.Exception, ctx), + fallbackAction: async (outcome, ctx, ct) => { await _fallbackAction(outcome.Exception, ctx, ct).ConfigureAwait(continueOnCapturedContext); - return EmptyStruct.Instance; - }, - continueOnCapturedContext); + return null; + }); } /// - protected override Task ImplementationAsync(Func> action, Context context, CancellationToken cancellationToken, - bool continueOnCapturedContext) - => - throw new InvalidOperationException($"You have executed the generic .Execute<{nameof(TResult)}> method on a non-generic {nameof(FallbackPolicy)}. A non-generic {nameof(FallbackPolicy)} only defines a fallback action which returns void; it can never return a substitute {nameof(TResult)} value. To use {nameof(FallbackPolicy)} to provide fallback {nameof(TResult)} values you must define a generic fallback policy {nameof(FallbackPolicy)}<{nameof(TResult)}>. For example, define the policy as Policy<{nameof(TResult)}>.Handle.Fallback<{nameof(TResult)}>(/* some {nameof(TResult)} value or Func<..., {nameof(TResult)}> */);"); + protected override Task AsyncGenericImplementation(TExecutableAsync action, Context context, + CancellationToken cancellationToken, bool continueOnCapturedContext) + => throw new InvalidOperationException($"You have executed the generic .Execute<{nameof(TResult)}> method on a non-generic {nameof(FallbackPolicy)}. A non-generic {nameof(FallbackPolicy)} only defines a fallback action which returns void; it can never return a substitute {nameof(TResult)} value. To use {nameof(FallbackPolicy)} to provide fallback {nameof(TResult)} values you must define a generic fallback policy {nameof(FallbackPolicy)}<{nameof(TResult)}>. For example, define the policy as Policy<{nameof(TResult)}>.Handle().Fallback<{nameof(TResult)}>(/* some {nameof(TResult)} value or Func<..., {nameof(TResult)}> */);"); } /// @@ -57,8 +52,8 @@ protected override Task ImplementationAsync(FuncThe return type of delegates which may be executed through the policy. public class AsyncFallbackPolicy : AsyncPolicy, IAsyncFallbackPolicy { - private Func, Context, Task> _onFallbackAsync; - private Func, Context, CancellationToken, Task> _fallbackAction; + private readonly Func, Context, Task> _onFallbackAsync; + private readonly Func, Context, CancellationToken, Task> _fallbackAction; internal AsyncFallbackPolicy( PolicyBuilder policyBuilder, @@ -72,16 +67,16 @@ Func, Context, CancellationToken, Task> fallbac /// [DebuggerStepThrough] - protected override Task ImplementationAsync(Func> action, Context context, CancellationToken cancellationToken, - bool continueOnCapturedContext) + protected override Task AsyncGenericImplementation(TExecutableAsync action, Context context, + CancellationToken cancellationToken, bool continueOnCapturedContext) => AsyncFallbackEngine.ImplementationAsync( action, context, cancellationToken, + continueOnCapturedContext, ExceptionPredicates, ResultPredicates, _onFallbackAsync, - _fallbackAction, - continueOnCapturedContext); + _fallbackAction); } } \ No newline at end of file diff --git a/src/Polly/Fallback/FallbackEngine.cs b/src/Polly/Fallback/FallbackEngine.cs index 075186d3615..776626c7cb2 100644 --- a/src/Polly/Fallback/FallbackEngine.cs +++ b/src/Polly/Fallback/FallbackEngine.cs @@ -5,14 +5,15 @@ namespace Polly.Fallback { internal static class FallbackEngine { - internal static TResult Implementation( - Func action, + internal static TResult Implementation( + in TExecutable action, Context context, CancellationToken cancellationToken, ExceptionPredicates shouldHandleExceptionPredicates, ResultPredicates shouldHandleResultPredicates, Action, Context> onFallback, Func, Context, CancellationToken, TResult> fallbackAction) + where TExecutable : ISyncExecutable { DelegateResult delegateOutcome; @@ -20,7 +21,7 @@ internal static TResult Implementation( { cancellationToken.ThrowIfCancellationRequested(); - TResult result = action(context, cancellationToken); + TResult result = action.Execute(context, cancellationToken); if (!shouldHandleResultPredicates.AnyMatch(result)) { diff --git a/src/Polly/Fallback/FallbackPolicy.cs b/src/Polly/Fallback/FallbackPolicy.cs index 7c43eadc53b..b13ab694636 100644 --- a/src/Polly/Fallback/FallbackPolicy.cs +++ b/src/Polly/Fallback/FallbackPolicy.cs @@ -1,7 +1,6 @@ using System; using System.Diagnostics; using System.Threading; -using Polly.Utilities; namespace Polly.Fallback { @@ -10,8 +9,8 @@ namespace Polly.Fallback /// public class FallbackPolicy : Policy, ISyncFallbackPolicy { - private Action _onFallback; - private Action _fallbackAction; + private readonly Action _onFallback; + private readonly Action _fallbackAction; internal FallbackPolicy( PolicyBuilder policyBuilder, @@ -25,19 +24,19 @@ internal FallbackPolicy( /// [DebuggerStepThrough] - protected override void Implementation(Action action, Context context, CancellationToken cancellationToken) - => FallbackEngine.Implementation( - (ctx, token) => { action(ctx, token); return EmptyStruct.Instance; }, - context, - cancellationToken, + protected override void SyncNonGenericImplementation(in TExecutable action, Context context, CancellationToken cancellationToken) + => FallbackEngine.Implementation( + action, + context, + cancellationToken, ExceptionPredicates, - ResultPredicates.None, - _onFallback == null ? (Action, Context>)null : (outcome, ctx) => _onFallback(outcome.Exception, ctx), - (outcome, ctx, ct) => { _fallbackAction(outcome.Exception, ctx, ct); return EmptyStruct.Instance; }); + ResultPredicates.None, + onFallback: _onFallback == null ? (Action, Context>)null : (outcome, ctx) => _onFallback(outcome.Exception, ctx), + fallbackAction: (outcome, ctx, ct) => { _fallbackAction(outcome.Exception, ctx, ct); return null; }); /// - protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken) - => throw new InvalidOperationException($"You have executed the generic .Execute<{nameof(TResult)}> method on a non-generic {nameof(FallbackPolicy)}. A non-generic {nameof(FallbackPolicy)} only defines a fallback action which returns void; it can never return a substitute {nameof(TResult)} value. To use {nameof(FallbackPolicy)} to provide fallback {nameof(TResult)} values you must define a generic fallback policy {nameof(FallbackPolicy)}<{nameof(TResult)}>. For example, define the policy as Policy<{nameof(TResult)}>.Handle.Fallback<{nameof(TResult)}>(/* some {nameof(TResult)} value or Func<..., {nameof(TResult)}> */);"); + protected override TResult SyncGenericImplementation(in TExecutable action, Context context, CancellationToken cancellationToken) + => throw new InvalidOperationException($"You have executed the generic .Execute<{nameof(TResult)}> method on a non-generic {nameof(FallbackPolicy)}. A non-generic {nameof(FallbackPolicy)} only defines a fallback action which returns void; it can never return a substitute {nameof(TResult)} value. To use {nameof(FallbackPolicy)} to provide fallback {nameof(TResult)} values you must define a generic fallback policy {nameof(FallbackPolicy)}<{nameof(TResult)}>. For example, define the policy as Policy<{nameof(TResult)}>.Handle().Fallback<{nameof(TResult)}>(/* some {nameof(TResult)} value or Func<..., {nameof(TResult)}> */);"); } /// @@ -46,8 +45,8 @@ protected override TResult Implementation(FuncThe return type of delegates which may be executed through the policy. public class FallbackPolicy : Policy, ISyncFallbackPolicy { - private Action, Context> _onFallback; - private Func, Context, CancellationToken, TResult> _fallbackAction; + private readonly Action, Context> _onFallback; + private readonly Func, Context, CancellationToken, TResult> _fallbackAction; internal FallbackPolicy( PolicyBuilder policyBuilder, @@ -61,7 +60,8 @@ Func, Context, CancellationToken, TResult> fallbackActio /// [DebuggerStepThrough] - protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken) + protected override TResult SyncGenericImplementation(in TExecutable action, Context context, + CancellationToken cancellationToken) => FallbackEngine.Implementation( action, context, diff --git a/src/Polly/IAsyncExecutable.cs b/src/Polly/IAsyncExecutable.cs new file mode 100644 index 00000000000..58cccc6d28e --- /dev/null +++ b/src/Polly/IAsyncExecutable.cs @@ -0,0 +1,28 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace Polly +{ + /// + /// Defines an operation that can be executed asynchronously with no return value. + /// + public interface IAsyncExecutable : IAsyncExecutable + { + } + + /// + /// Defines an operation that can be executed asynchronously to return a promise of a result of type + /// + /// The return type of the operation. + public interface IAsyncExecutable + { + /// + /// Asynchronously executes the operation represented by the instance. + /// + /// The Polly execution to execute the operation with. + /// A governing cancellation of the executed operation. + /// Whether continuing after an awaited operation should continue of a captured + /// A promise of a result of type + Task ExecuteAsync(Context context, CancellationToken cancellationToken, bool continueOnCapturedContext); + } +} \ No newline at end of file diff --git a/src/Polly/IAsyncPolicy.TResult.cs b/src/Polly/IAsyncPolicy.TResult.cs index d7c10de9363..902ea425572 100644 --- a/src/Polly/IAsyncPolicy.TResult.cs +++ b/src/Polly/IAsyncPolicy.TResult.cs @@ -19,14 +19,14 @@ public interface IAsyncPolicy : IsPolicy IAsyncPolicy WithPolicyKey(String policyKey); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The action to perform. /// The value returned by the action Task ExecuteAsync(Func> action); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The action to perform. /// Context data that is passed to the exception policy. @@ -34,7 +34,7 @@ public interface IAsyncPolicy : IsPolicy Task ExecuteAsync(Func> action, Context context); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The action to perform. /// Arbitrary data that is passed to the exception policy. @@ -42,7 +42,7 @@ public interface IAsyncPolicy : IsPolicy Task ExecuteAsync(Func> action, IDictionary contextData); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The action to perform. /// A cancellation token which can be used to cancel the action. When a retry policy is in use, also cancels any further retries. @@ -50,7 +50,7 @@ public interface IAsyncPolicy : IsPolicy Task ExecuteAsync(Func> action, CancellationToken cancellationToken); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The action to perform. /// Arbitrary data that is passed to the exception policy. @@ -59,7 +59,7 @@ public interface IAsyncPolicy : IsPolicy Task ExecuteAsync(Func> action, IDictionary contextData, CancellationToken cancellationToken); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The action to perform. /// Context data that is passed to the exception policy. @@ -68,7 +68,7 @@ public interface IAsyncPolicy : IsPolicy Task ExecuteAsync(Func> action, Context context, CancellationToken cancellationToken); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The action to perform. /// Whether to continue on a captured synchronization context. @@ -78,7 +78,7 @@ public interface IAsyncPolicy : IsPolicy Task ExecuteAsync(Func> action, CancellationToken cancellationToken, bool continueOnCapturedContext); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The action to perform. /// Arbitrary data that is passed to the exception policy. @@ -89,7 +89,7 @@ public interface IAsyncPolicy : IsPolicy Task ExecuteAsync(Func> action, IDictionary contextData, CancellationToken cancellationToken, bool continueOnCapturedContext); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The action to perform. /// Context data that is passed to the exception policy. @@ -99,6 +99,32 @@ public interface IAsyncPolicy : IsPolicy /// Please use asynchronous-defined policies when calling asynchronous ExecuteAsync (and similar) methods. Task ExecuteAsync(Func> action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext); + /// + /// Executes the specified asynchronous function within the policy, passing an extra input of user-defined type , and returns the result. + /// + /// The function to execute. + /// Context data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The type of the first custom input to the function. + /// The value returned by the function + Task ExecuteAsync(Func> func, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, T1 input1); + + /// + /// Executes the specified asynchronous function within the policy, passing two extra inputs of user-defined types and , and returns the result. + /// + /// The function to execute. + /// Context data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The value of the second custom input to the function. + /// The type of the first custom input to the function. + /// The type of the second custom input to the function. + /// The value returned by the function + Task ExecuteAsync(Func> func, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, T1 input1, T2 input2); + /// /// Executes the specified asynchronous action within the policy and returns the result. /// @@ -124,7 +150,7 @@ public interface IAsyncPolicy : IsPolicy Task> ExecuteAndCaptureAsync(Func> action, Context context); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The action to perform. /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. @@ -132,7 +158,7 @@ public interface IAsyncPolicy : IsPolicy Task> ExecuteAndCaptureAsync(Func> action, CancellationToken cancellationToken); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The action to perform. /// Arbitrary data that is passed to the exception policy. @@ -142,7 +168,7 @@ public interface IAsyncPolicy : IsPolicy Task> ExecuteAndCaptureAsync(Func> action, IDictionary contextData, CancellationToken cancellationToken); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The action to perform. /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. @@ -151,7 +177,7 @@ public interface IAsyncPolicy : IsPolicy Task> ExecuteAndCaptureAsync(Func> action, Context context, CancellationToken cancellationToken); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The action to perform. /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. @@ -161,7 +187,7 @@ public interface IAsyncPolicy : IsPolicy Task> ExecuteAndCaptureAsync(Func> action, CancellationToken cancellationToken, bool continueOnCapturedContext); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The action to perform. /// Arbitrary data that is passed to the exception policy. @@ -172,7 +198,7 @@ public interface IAsyncPolicy : IsPolicy Task> ExecuteAndCaptureAsync(Func> action, IDictionary contextData, CancellationToken cancellationToken, bool continueOnCapturedContext); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The action to perform. /// Context data that is passed to the exception policy. @@ -181,5 +207,31 @@ public interface IAsyncPolicy : IsPolicy /// The captured result /// Please use asynchronous-defined policies when calling asynchronous ExecuteAsync (and similar) methods. Task> ExecuteAndCaptureAsync(Func> action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext); + + /// + /// Executes the specified asynchronous function within the policy, passing an extra input of user-defined type , and returns the captured result. + /// + /// The function to execute. + /// Context data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The type of the first custom input to the function. + /// The outcome of the execution, as a promise of a captured + Task> ExecuteAndCaptureAsync(Func> func, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, T1 input1); + + /// + /// Executes the specified asynchronous function within the policy, passing two extra inputs of user-defined types and , and returns the result. + /// + /// The function to execute. + /// Context data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The value of the second custom input to the function. + /// The type of the first custom input to the function. + /// The type of the second custom input to the function. + /// The outcome of the execution, as a promise of a captured + Task> ExecuteAndCaptureAsync(Func> func, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, T1 input1, T2 input2); } } diff --git a/src/Polly/IAsyncPolicy.cs b/src/Polly/IAsyncPolicy.cs index f6ff5f9fff4..524254b14ed 100644 --- a/src/Polly/IAsyncPolicy.cs +++ b/src/Polly/IAsyncPolicy.cs @@ -18,34 +18,34 @@ public interface IAsyncPolicy : IsPolicy IAsyncPolicy WithPolicyKey(String policyKey); /// - /// Executes the specified asynchronous action within the policy. + /// Executes the specified asynchronous action within the policy. /// /// The action to perform. Task ExecuteAsync(Func action); /// - /// Executes the specified asynchronous action within the policy. + /// Executes the specified asynchronous action within the policy. /// /// The action to perform. /// Arbitrary data that is passed to the exception policy. Task ExecuteAsync(Func action, IDictionary contextData); /// - /// Executes the specified asynchronous action within the policy. + /// Executes the specified asynchronous action within the policy. /// /// The action to perform. /// Context data that is passed to the exception policy. Task ExecuteAsync(Func action, Context context); /// - /// Executes the specified asynchronous action within the policy. + /// Executes the specified asynchronous action within the policy. /// /// The action to perform. /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. Task ExecuteAsync(Func action, CancellationToken cancellationToken); /// - /// Executes the specified asynchronous action within the policy. + /// Executes the specified asynchronous action within the policy. /// /// The action to perform. /// Arbitrary data that is passed to the exception policy. @@ -53,7 +53,7 @@ public interface IAsyncPolicy : IsPolicy Task ExecuteAsync(Func action, IDictionary contextData, CancellationToken cancellationToken); /// - /// Executes the specified asynchronous action within the policy. + /// Executes the specified asynchronous action within the policy. /// /// The action to perform. /// Context data that is passed to the exception policy. @@ -61,7 +61,7 @@ public interface IAsyncPolicy : IsPolicy Task ExecuteAsync(Func action, Context context, CancellationToken cancellationToken); /// - /// Executes the specified asynchronous action within the policy. + /// Executes the specified asynchronous action within the policy. /// /// The action to perform. /// Whether to continue on a captured synchronization context. @@ -70,7 +70,7 @@ public interface IAsyncPolicy : IsPolicy Task ExecuteAsync(Func action, CancellationToken cancellationToken, bool continueOnCapturedContext); /// - /// Executes the specified asynchronous action within the policy. + /// Executes the specified asynchronous action within the policy. /// /// The action to perform. /// Arbitrary data that is passed to the exception policy. /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. @@ -79,7 +79,7 @@ public interface IAsyncPolicy : IsPolicy Task ExecuteAsync(Func action, IDictionary contextData, CancellationToken cancellationToken, bool continueOnCapturedContext); /// - /// Executes the specified asynchronous action within the policy. + /// Executes the specified asynchronous action within the policy. /// /// The action to perform. /// Context data that is passed to the exception policy. @@ -89,7 +89,31 @@ public interface IAsyncPolicy : IsPolicy Task ExecuteAsync(Func action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy, passing an extra input of user-defined type . + /// + /// The action to perform. + /// Context data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The type of the first custom input to the function. + Task ExecuteAsync(Func action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, T1 input1); + + /// + /// Executes the specified asynchronous action within the policy, passing two extra inputs of user-defined types and . + /// + /// The action to perform. + /// Context data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The value of the second custom input to the function. + /// The type of the first custom input to the function. + /// The type of the second custom input to the function. + Task ExecuteAsync(Func action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, T1 input1, T2 input2); + + /// + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The type of the result. /// The action to perform. @@ -97,7 +121,7 @@ public interface IAsyncPolicy : IsPolicy Task ExecuteAsync(Func> action); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The type of the result. /// The action to perform. @@ -106,7 +130,7 @@ public interface IAsyncPolicy : IsPolicy Task ExecuteAsync(Func> action, Context context); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The action to perform. /// Arbitrary data that is passed to the exception policy. @@ -114,7 +138,7 @@ public interface IAsyncPolicy : IsPolicy Task ExecuteAsync(Func> action, IDictionary contextData); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The type of the result. /// The action to perform. @@ -123,7 +147,7 @@ public interface IAsyncPolicy : IsPolicy Task ExecuteAsync(Func> action, CancellationToken cancellationToken); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The action to perform. /// Arbitrary data that is passed to the exception policy. @@ -132,7 +156,7 @@ public interface IAsyncPolicy : IsPolicy Task ExecuteAsync(Func> action, IDictionary contextData, CancellationToken cancellationToken); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The type of the result. /// The action to perform. @@ -142,7 +166,7 @@ public interface IAsyncPolicy : IsPolicy Task ExecuteAsync(Func> action, Context context, CancellationToken cancellationToken); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The type of the result. /// The action to perform. @@ -153,7 +177,7 @@ public interface IAsyncPolicy : IsPolicy Task ExecuteAsync(Func> action, CancellationToken cancellationToken, bool continueOnCapturedContext); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The action to perform. /// Arbitrary data that is passed to the exception policy. @@ -164,7 +188,7 @@ public interface IAsyncPolicy : IsPolicy Task ExecuteAsync(Func> action, IDictionary contextData, CancellationToken cancellationToken, bool continueOnCapturedContext); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The type of the result. /// The action to perform. @@ -176,14 +200,42 @@ public interface IAsyncPolicy : IsPolicy Task ExecuteAsync(Func> action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext); /// - /// Executes the specified asynchronous action within the policy and returns the captured result. + /// Executes the specified asynchronous function within the policy, passing an extra input of user-defined type , and returns the result. + /// + /// The type of the result. + /// The function to execute. + /// Context data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The type of the first custom input to the function. + /// The value returned by the function + Task ExecuteAsync(Func> func, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, T1 input1); + + /// + /// Executes the specified asynchronous function within the policy, passing two extra inputs of user-defined types and , and returns the result. + /// + /// The type of the result. + /// The function to execute. + /// Context data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The value of the second custom input to the function. + /// The type of the first custom input to the function. + /// The type of the second custom input to the function. + /// The value returned by the function + Task ExecuteAsync(Func> func, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, T1 input1, T2 input2); + + /// + /// Executes the specified asynchronous action within the policy and returns the captured result. /// /// The action to perform. /// The captured result Task ExecuteAndCaptureAsync(Func action); /// - /// Executes the specified asynchronous action within the policy and returns the captured result. + /// Executes the specified asynchronous action within the policy and returns the captured result. /// /// The action to perform. /// Arbitrary data that is passed to the exception policy. @@ -192,7 +244,7 @@ public interface IAsyncPolicy : IsPolicy Task ExecuteAndCaptureAsync(Func action, IDictionary contextData); /// - /// Executes the specified asynchronous action within the policy and returns the captured result. + /// Executes the specified asynchronous action within the policy and returns the captured result. /// /// The action to perform. /// Context data that is passed to the exception policy. @@ -200,14 +252,14 @@ public interface IAsyncPolicy : IsPolicy Task ExecuteAndCaptureAsync(Func action, Context context); /// - /// Executes the specified asynchronous action within the policy and returns the captured result. + /// Executes the specified asynchronous action within the policy and returns the captured result. /// /// The action to perform. /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. Task ExecuteAndCaptureAsync(Func action, CancellationToken cancellationToken); /// - /// Executes the specified asynchronous action within the policy and returns the captured result. + /// Executes the specified asynchronous action within the policy and returns the captured result. /// /// The action to perform. /// Arbitrary data that is passed to the exception policy. @@ -217,7 +269,7 @@ public interface IAsyncPolicy : IsPolicy Task ExecuteAndCaptureAsync(Func action, IDictionary contextData, CancellationToken cancellationToken); /// - /// Executes the specified asynchronous action within the policy and returns the captured result. + /// Executes the specified asynchronous action within the policy and returns the captured result. /// /// The action to perform. /// Context data that is passed to the exception policy. @@ -225,7 +277,7 @@ public interface IAsyncPolicy : IsPolicy Task ExecuteAndCaptureAsync(Func action, Context context, CancellationToken cancellationToken); /// - /// Executes the specified asynchronous action within the policy and returns the captured result. + /// Executes the specified asynchronous action within the policy and returns the captured result. /// /// The action to perform. /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. @@ -234,7 +286,7 @@ public interface IAsyncPolicy : IsPolicy Task ExecuteAndCaptureAsync(Func action, CancellationToken cancellationToken, bool continueOnCapturedContext); /// - /// Executes the specified asynchronous action within the policy and returns the captured result. + /// Executes the specified asynchronous action within the policy and returns the captured result. /// /// The action to perform. /// Arbitrary data that is passed to the exception policy. @@ -245,7 +297,7 @@ public interface IAsyncPolicy : IsPolicy Task ExecuteAndCaptureAsync(Func action, IDictionary contextData, CancellationToken cancellationToken, bool continueOnCapturedContext); /// - /// Executes the specified asynchronous action within the policy and returns the captured result. + /// Executes the specified asynchronous action within the policy and returns the captured result. /// /// The action to perform. /// Context data that is passed to the exception policy. @@ -254,6 +306,32 @@ public interface IAsyncPolicy : IsPolicy /// Please use asynchronous-defined policies when calling asynchronous ExecuteAsync (and similar) methods. Task ExecuteAndCaptureAsync(Func action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext); + /// + /// Executes the specified asynchronous action within the policy, passing an extra input of user-defined type . + /// + /// The action to perform. + /// Context data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The type of the first custom input to the function. + /// The outcome of the execution, as a promise of a captured + Task ExecuteAndCaptureAsync(Func action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, T1 input1); + + /// + /// Executes the specified asynchronous action within the policy, passing two extra inputs of user-defined types and . + /// + /// The action to perform. + /// Context data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The value of the second custom input to the function. + /// The type of the first custom input to the function. + /// The type of the second custom input to the function. + /// The outcome of the execution, as a promise of a captured + Task ExecuteAndCaptureAsync(Func action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, T1 input1, T2 input2); + /// /// Executes the specified asynchronous action within the policy and returns the result. /// @@ -282,7 +360,7 @@ public interface IAsyncPolicy : IsPolicy Task> ExecuteAndCaptureAsync(Func> action, Context context); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The type of the result. /// The action to perform. @@ -291,7 +369,7 @@ public interface IAsyncPolicy : IsPolicy Task> ExecuteAndCaptureAsync(Func> action, CancellationToken cancellationToken); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The type of the result. /// The action to perform. @@ -302,7 +380,7 @@ public interface IAsyncPolicy : IsPolicy Task> ExecuteAndCaptureAsync(Func> action, IDictionary contextData, CancellationToken cancellationToken); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The type of the result. /// The action to perform. @@ -312,7 +390,7 @@ public interface IAsyncPolicy : IsPolicy Task> ExecuteAndCaptureAsync(Func> action, Context context, CancellationToken cancellationToken); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The type of the result. /// The action to perform. @@ -323,7 +401,7 @@ public interface IAsyncPolicy : IsPolicy Task> ExecuteAndCaptureAsync(Func> action, CancellationToken cancellationToken, bool continueOnCapturedContext); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The type of the result. /// The action to perform. @@ -335,7 +413,7 @@ public interface IAsyncPolicy : IsPolicy Task> ExecuteAndCaptureAsync(Func> action, IDictionary contextData, CancellationToken cancellationToken, bool continueOnCapturedContext); /// - /// Executes the specified asynchronous action within the policy and returns the result. + /// Executes the specified asynchronous action within the policy and returns the result. /// /// The type of the result. /// The action to perform. @@ -345,5 +423,33 @@ public interface IAsyncPolicy : IsPolicy /// The captured result /// Please use asynchronous-defined policies when calling asynchronous ExecuteAsync (and similar) methods. Task> ExecuteAndCaptureAsync(Func> action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext); + + /// + /// Executes the specified asynchronous function within the policy, passing an extra input of user-defined type , and returns the captured result. + /// + /// The type of the result. + /// The function to execute. + /// Context data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The type of the first custom input to the function. + /// The outcome of the execution, as a promise of a captured + Task> ExecuteAndCaptureAsync(Func> func, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, T1 input1); + + /// + /// Executes the specified asynchronous function within the policy, passing two extra inputs of user-defined types and , and returns the result. + /// + /// The type of the result. + /// The function to execute. + /// Context data that is passed to the exception policy. + /// Whether to continue on a captured synchronization context. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The value of the second custom input to the function. + /// The type of the first custom input to the function. + /// The type of the second custom input to the function. + /// The outcome of the execution, as a promise of a captured + Task> ExecuteAndCaptureAsync(Func> func, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, T1 input1, T2 input2); } } diff --git a/src/Polly/IAsyncPolicyInternal.TResult.cs b/src/Polly/IAsyncPolicyInternal.TResult.cs new file mode 100644 index 00000000000..5107052d7f0 --- /dev/null +++ b/src/Polly/IAsyncPolicyInternal.TResult.cs @@ -0,0 +1,14 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace Polly +{ + internal interface IAsyncPolicyInternal + { + Task ExecuteAsync(TExecutableAsync action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) + where TExecutableAsync : IAsyncExecutable; + + Task> ExecuteAndCaptureAsync(TExecutableAsync action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) + where TExecutableAsync : IAsyncExecutable; + } +} \ No newline at end of file diff --git a/src/Polly/IAsyncPolicyInternal.cs b/src/Polly/IAsyncPolicyInternal.cs new file mode 100644 index 00000000000..aa770cee941 --- /dev/null +++ b/src/Polly/IAsyncPolicyInternal.cs @@ -0,0 +1,21 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace Polly +{ + internal interface IAsyncPolicyInternal + { + Task ExecuteAsync(TExecutableAsync action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) + where TExecutableAsync : IAsyncExecutable; + + Task ExecuteAsync(TExecutableAsync action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) + where TExecutableAsync : IAsyncExecutable; + + Task ExecuteAndCaptureAsync(TExecutableAsync action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) + where TExecutableAsync : IAsyncExecutable; + + + Task> ExecuteAndCaptureAsync(TExecutableAsync action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) + where TExecutableAsync : IAsyncExecutable; + } +} \ No newline at end of file diff --git a/src/Polly/IExceptionPredicates.cs b/src/Polly/IExceptionPredicates.cs new file mode 100644 index 00000000000..c1d06fcaccf --- /dev/null +++ b/src/Polly/IExceptionPredicates.cs @@ -0,0 +1,7 @@ +namespace Polly +{ + internal interface IExceptionPredicates + { + ExceptionPredicates PredicatesInternal { get; } + } +} diff --git a/src/Polly/IResultPredicates.cs b/src/Polly/IResultPredicates.cs new file mode 100644 index 00000000000..677e264dffd --- /dev/null +++ b/src/Polly/IResultPredicates.cs @@ -0,0 +1,7 @@ +namespace Polly +{ + internal interface IResultPredicates + { + ResultPredicates PredicatesInternal { get; } + } +} diff --git a/src/Polly/ISyncExecutable.cs b/src/Polly/ISyncExecutable.cs new file mode 100644 index 00000000000..37e78b34406 --- /dev/null +++ b/src/Polly/ISyncExecutable.cs @@ -0,0 +1,26 @@ +using System.Threading; + +namespace Polly +{ + /// + /// Defines an operation that can be executed synchronously, with no return result. + /// + public interface ISyncExecutable : ISyncExecutable + { + } + + /// + /// Defines an operation that can be executed synchronously to return a result of type + /// + /// The return type of the operation. + public interface ISyncExecutable + { + /// + /// Synchronously executes the operation represented by the instance. + /// + /// The Polly execution to execute the operation with. + /// A governing cancellation of the executed operation. + /// A result of type + TResult Execute(Context context, CancellationToken cancellationToken); + } +} diff --git a/src/Polly/ISyncPolicy.TResult.cs b/src/Polly/ISyncPolicy.TResult.cs index 13ee2a9224b..3c0bec5d09e 100644 --- a/src/Polly/ISyncPolicy.TResult.cs +++ b/src/Polly/ISyncPolicy.TResult.cs @@ -127,5 +127,53 @@ public interface ISyncPolicy : IsPolicy /// The cancellation token. /// The captured result PolicyResult ExecuteAndCapture(Func action, Context context, CancellationToken cancellationToken); + + /// + /// Executes the specified synchronous function within the policy, passing an extra input of user-defined type , and returns the result. + /// + /// The function to execute. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The type of the first custom input to the function. + /// The value returned by the function + TResult Execute(Func func, Context context, CancellationToken cancellationToken, T1 input1); + + /// + /// Executes the specified synchronous function within the policy, passing two extra inputs of user-defined types and , and returns the result. + /// + /// The function to execute. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The value of the second custom input to the function. + /// The type of the first custom input to the function. + /// The type of the second custom input to the function. + /// The value returned by the function + TResult Execute(Func func, Context context, CancellationToken cancellationToken, T1 input1, T2 input2); + + /// + /// Executes the specified synchronous function within the policy, passing an extra input of user-defined type , and returns the captured result. + /// + /// The function to execute. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The type of the first custom input to the function. + /// The outcome of the execution, as a captured + PolicyResult ExecuteAndCapture(Func func, Context context, CancellationToken cancellationToken, T1 input1); + + /// + /// Executes the specified synchronous function within the policy, passing two extra inputs of user-defined types and , and returns the result. + /// + /// The function to execute. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The value of the second custom input to the function. + /// The type of the first custom input to the function. + /// The type of the second custom input to the function. + /// The outcome of the execution, as a captured + PolicyResult ExecuteAndCapture(Func func, Context context, CancellationToken cancellationToken, T1 input1, T2 input2); } } diff --git a/src/Polly/ISyncPolicy.cs b/src/Polly/ISyncPolicy.cs index 87d1c28fce2..242aaa88c75 100644 --- a/src/Polly/ISyncPolicy.cs +++ b/src/Polly/ISyncPolicy.cs @@ -60,6 +60,28 @@ public interface ISyncPolicy : IsPolicy /// The cancellation token. void Execute(Action action, Context context, CancellationToken cancellationToken); + /// + /// Executes the specified synchronous action within the policy, passing an extra input of user-defined type . + /// + /// The action to perform. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The type of the first custom input to the function. + void Execute(Action action, Context context, CancellationToken cancellationToken, T1 input1); + + /// + /// Executes the specified synchronous action within the policy, passing two extra inputs of user-defined types and . + /// + /// The action to perform. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The value of the second custom input to the function. + /// The type of the first custom input to the function. + /// The type of the second custom input to the function. + void Execute(Action action, Context context, CancellationToken cancellationToken, T1 input1, T2 input2); + /// /// Executes the specified action within the policy and returns the Result. /// @@ -124,6 +146,32 @@ public interface ISyncPolicy : IsPolicy /// The value returned by the action TResult Execute(Func action, Context context, CancellationToken cancellationToken); + /// + /// Executes the specified synchronous function within the policy, passing an extra input of user-defined type , and returns the result. + /// + /// The type of the result. + /// The function to execute. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The type of the first custom input to the function. + /// The value returned by the function + TResult Execute(Func func, Context context, CancellationToken cancellationToken, T1 input1); + + /// + /// Executes the specified synchronous function within the policy, passing two extra inputs of user-defined types and , and returns the result. + /// + /// The type of the result. + /// The function to execute. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The value of the second custom input to the function. + /// The type of the first custom input to the function. + /// The type of the second custom input to the function. + /// The value returned by the function + TResult Execute(Func func, Context context, CancellationToken cancellationToken, T1 input1, T2 input2); + /// /// Executes the specified action within the policy and returns the captured result /// @@ -175,6 +223,30 @@ public interface ISyncPolicy : IsPolicy /// The captured result PolicyResult ExecuteAndCapture(Action action, Context context, CancellationToken cancellationToken); + /// + /// Executes the specified synchronous action within the policy, passing an extra input of user-defined type . + /// + /// The action to perform. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The type of the first custom input to the function. + /// The outcome of the execution, as a captured + PolicyResult ExecuteAndCapture(Action action, Context context, CancellationToken cancellationToken, T1 input1); + + /// + /// Executes the specified synchronous action within the policy, passing two extra inputs of user-defined types and . + /// + /// The action to perform. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The value of the second custom input to the function. + /// The type of the first custom input to the function. + /// The type of the second custom input to the function. + /// The outcome of the execution, as a captured + PolicyResult ExecuteAndCapture(Action action, Context context, CancellationToken cancellationToken, T1 input1, T2 input2); + /// /// Executes the specified action within the policy and returns the captured result /// @@ -228,5 +300,31 @@ public interface ISyncPolicy : IsPolicy /// The cancellation token. /// The captured result PolicyResult ExecuteAndCapture(Func action, Context context, CancellationToken cancellationToken); + + /// + /// Executes the specified synchronous function within the policy, passing an extra input of user-defined type , and returns the captured result. + /// + /// The type of the result. + /// The function to execute. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The type of the first custom input to the function. + /// The outcome of the execution, as a captured + PolicyResult ExecuteAndCapture(Func func, Context context, CancellationToken cancellationToken, T1 input1); + + /// + /// Executes the specified synchronous function within the policy, passing two extra inputs of user-defined types and , and returns the result. + /// + /// The type of the result. + /// The function to execute. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The value of the second custom input to the function. + /// The type of the first custom input to the function. + /// The type of the second custom input to the function. + /// The outcome of the execution, as a captured + PolicyResult ExecuteAndCapture(Func func, Context context, CancellationToken cancellationToken, T1 input1, T2 input2); } } diff --git a/src/Polly/ISyncPolicyInternal.TResult.cs b/src/Polly/ISyncPolicyInternal.TResult.cs new file mode 100644 index 00000000000..6ae45a37db8 --- /dev/null +++ b/src/Polly/ISyncPolicyInternal.TResult.cs @@ -0,0 +1,13 @@ +using System.Threading; + +namespace Polly +{ + internal interface ISyncPolicyInternal + { + TResult Execute(in TExecutable action, Context context, CancellationToken cancellationToken) + where TExecutable : ISyncExecutable; + + PolicyResult ExecuteAndCapture(in TExecutable action, Context context, CancellationToken cancellationToken) + where TExecutable : ISyncExecutable; + } +} diff --git a/src/Polly/ISyncPolicyInternal.cs b/src/Polly/ISyncPolicyInternal.cs new file mode 100644 index 00000000000..5bfacf841eb --- /dev/null +++ b/src/Polly/ISyncPolicyInternal.cs @@ -0,0 +1,19 @@ +using System.Threading; + +namespace Polly +{ + internal interface ISyncPolicyInternal + { + void Execute(in TExecutable action, Context context, CancellationToken cancellationToken) + where TExecutable : ISyncExecutable; + + TResult Execute(in TExecutable action, Context context, CancellationToken cancellationToken) + where TExecutable : ISyncExecutable; + + PolicyResult ExecuteAndCapture(in TExecutable action, Context context, CancellationToken cancellationToken) + where TExecutable : ISyncExecutable; + + PolicyResult ExecuteAndCapture(in TExecutable action, Context context, CancellationToken cancellationToken) + where TExecutable : ISyncExecutable; + } +} diff --git a/src/Polly/NoOp/AsyncNoOpEngine.cs b/src/Polly/NoOp/AsyncNoOpEngine.cs new file mode 100644 index 00000000000..918c4dc6330 --- /dev/null +++ b/src/Polly/NoOp/AsyncNoOpEngine.cs @@ -0,0 +1,14 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace Polly.NoOp +{ + internal static class AsyncNoOpEngine + { + internal static Task ImplementationAsync(TExecutableAsync action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) + where TExecutableAsync : IAsyncExecutable + { + return action.ExecuteAsync(context, cancellationToken, continueOnCapturedContext); + } + } +} diff --git a/src/Polly/NoOp/AsyncNoOpPolicy.cs b/src/Polly/NoOp/AsyncNoOpPolicy.cs index 52496d52a29..d99340f9fa0 100644 --- a/src/Polly/NoOp/AsyncNoOpPolicy.cs +++ b/src/Polly/NoOp/AsyncNoOpPolicy.cs @@ -1,5 +1,4 @@ -using System; -using System.Diagnostics; +using System.Diagnostics; using System.Threading; using System.Threading.Tasks; @@ -16,9 +15,12 @@ internal AsyncNoOpPolicy() /// [DebuggerStepThrough] - protected override Task ImplementationAsync( Func> action, Context context, CancellationToken cancellationToken, + protected override Task AsyncGenericImplementation( + TExecutableAsync action, + Context context, + CancellationToken cancellationToken, bool continueOnCapturedContext) - => NoOpEngine.ImplementationAsync(action, context, cancellationToken, continueOnCapturedContext); + => AsyncNoOpEngine.ImplementationAsync(action, context, cancellationToken, continueOnCapturedContext); } /// @@ -33,8 +35,11 @@ internal AsyncNoOpPolicy() /// [DebuggerStepThrough] - protected override Task ImplementationAsync(Func> action, Context context, CancellationToken cancellationToken, + protected override Task AsyncGenericImplementation( + TExecutableAsync action, + Context context, + CancellationToken cancellationToken, bool continueOnCapturedContext) - => NoOpEngine.ImplementationAsync(action, context, cancellationToken, continueOnCapturedContext); + => AsyncNoOpEngine.ImplementationAsync(action, context, cancellationToken, continueOnCapturedContext); } } \ No newline at end of file diff --git a/src/Polly/NoOp/NoOpEngine.cs b/src/Polly/NoOp/NoOpEngine.cs index 84c7c450623..4bfbe91f67c 100644 --- a/src/Polly/NoOp/NoOpEngine.cs +++ b/src/Polly/NoOp/NoOpEngine.cs @@ -1,11 +1,13 @@ -using System; -using System.Threading; +using System.Threading; namespace Polly.NoOp { - internal static partial class NoOpEngine + internal static class NoOpEngine { - internal static TResult Implementation(Func action, Context context, CancellationToken cancellationToken) - => action(context, cancellationToken); + internal static TResult Implementation(in TExecutable action, Context context, CancellationToken cancellationToken) + where TExecutable : ISyncExecutable + { + return action.Execute(context, cancellationToken); + } } } diff --git a/src/Polly/NoOp/NoOpEngineAsync.cs b/src/Polly/NoOp/NoOpEngineAsync.cs deleted file mode 100644 index bd4f1a5db6f..00000000000 --- a/src/Polly/NoOp/NoOpEngineAsync.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Polly.NoOp -{ - internal static partial class NoOpEngine - { - internal static async Task ImplementationAsync(Func> action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) - => await action(context, cancellationToken).ConfigureAwait(continueOnCapturedContext); - } -} diff --git a/src/Polly/NoOp/NoOpPolicy.cs b/src/Polly/NoOp/NoOpPolicy.cs index 65acee00c68..f61393d1e2e 100644 --- a/src/Polly/NoOp/NoOpPolicy.cs +++ b/src/Polly/NoOp/NoOpPolicy.cs @@ -1,5 +1,4 @@ -using System; -using System.Diagnostics; +using System.Diagnostics; using System.Threading; namespace Polly.NoOp @@ -15,8 +14,10 @@ internal NoOpPolicy() /// [DebuggerStepThrough] - protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken) - => NoOpEngine.Implementation(action, context, cancellationToken); + protected override TResult SyncGenericImplementation(in TExecutable action, Context context, CancellationToken cancellationToken) + { + return NoOpEngine.Implementation(action, context, cancellationToken); + } } /// @@ -31,7 +32,9 @@ internal NoOpPolicy() /// [DebuggerStepThrough] - protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken) - => NoOpEngine.Implementation(action, context, cancellationToken); + protected override TResult SyncGenericImplementation(in TExecutable action, Context context, CancellationToken cancellationToken) + { + return NoOpEngine.Implementation(action, context, cancellationToken); + } } } diff --git a/src/Polly/Policy.ExecuteOverloads.cs b/src/Polly/Policy.ExecuteOverloads.cs deleted file mode 100644 index 96b671617ac..00000000000 --- a/src/Polly/Policy.ExecuteOverloads.cs +++ /dev/null @@ -1,335 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Threading; - -namespace Polly -{ - public abstract partial class Policy : ISyncPolicy - { - #region Execute overloads - - /// - /// Executes the specified action within the policy. - /// - /// The action to perform. - [DebuggerStepThrough] - public void Execute(Action action) - => Execute((ctx, ct) => action(), new Context(), DefaultCancellationToken); - - /// - /// Executes the specified action within the policy. - /// - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - [DebuggerStepThrough] - public void Execute(Action action, IDictionary contextData) - => Execute((ctx, ct) => action(ctx), new Context(contextData), DefaultCancellationToken); - - /// - /// Executes the specified action within the policy. - /// - /// The action to perform. - /// Context data that is passed to the exception policy. - [DebuggerStepThrough] - public void Execute(Action action, Context context) - => Execute((ctx, ct) => action(ctx), context, DefaultCancellationToken); - - /// - /// Executes the specified action within the policy - /// - /// - /// - [DebuggerStepThrough] - public void Execute(Action action, CancellationToken cancellationToken) - => Execute((ctx, ct) => action(ct), new Context(), cancellationToken); - - /// - /// Executes the specified action within the policy. - /// - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - /// The cancellation token. - /// contextData - [DebuggerStepThrough] - public void Execute(Action action, IDictionary contextData, CancellationToken cancellationToken) - => Execute(action, new Context(contextData), cancellationToken); - - /// - /// Executes the specified action within the policy. - /// - /// The action to perform. - /// Context data that is passed to the exception policy. - /// The cancellation token. - [DebuggerStepThrough] - public void Execute(Action action, Context context, CancellationToken cancellationToken) - { - if (context == null) throw new ArgumentNullException(nameof(context)); - - SetPolicyContext(context, out string priorPolicyWrapKey, out string priorPolicyKey); - - try - { - Implementation(action, context, cancellationToken); - } - finally - { - RestorePolicyContext(context, priorPolicyWrapKey, priorPolicyKey); - } - } - - #region Overloads method-generic in TResult - - /// - /// Executes the specified action within the policy and returns the Result. - /// - /// The type of the Result. - /// The action to perform. - /// The value returned by the action - [DebuggerStepThrough] - public TResult Execute(Func action) - => Execute((ctx, ct) => action(), new Context(), DefaultCancellationToken); - - /// - /// Executes the specified action within the policy and returns the result. - /// - /// The type of the result. - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - /// contextData - /// - /// The value returned by the action - /// - /// contextData - [DebuggerStepThrough] - public TResult Execute(Func action, IDictionary contextData) - => Execute((ctx, ct) => action(ctx), new Context(contextData), DefaultCancellationToken); - - /// - /// Executes the specified action within the policy and returns the result. - /// - /// The type of the result. - /// The action to perform. - /// Context data that is passed to the exception policy. - /// contextData - /// - /// The value returned by the action - /// - /// contextData - [DebuggerStepThrough] - public TResult Execute(Func action, Context context) - => Execute((ctx, ct) => action(ctx), context, DefaultCancellationToken); - - /// - /// Executes the specified action within the policy and returns the result. - /// - /// The type of the result. - /// The action to perform. - /// The cancellation token. - /// The value returned by the action - [DebuggerStepThrough] - public TResult Execute(Func action, CancellationToken cancellationToken) - => Execute((ctx, ct) => action(ct), new Context(), cancellationToken); - - /// - /// Executes the specified action within the policy and returns the result. - /// - /// The type of the result. - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - /// The cancellation token. - /// The value returned by the action - /// contextData - [DebuggerStepThrough] - public TResult Execute(Func action, IDictionary contextData, CancellationToken cancellationToken) - => Execute(action, new Context(contextData), cancellationToken); - - /// - /// Executes the specified action within the policy and returns the result. - /// - /// The type of the result. - /// The action to perform. - /// Context data that is passed to the exception policy. - /// The cancellation token. - /// The value returned by the action - [DebuggerStepThrough] - public TResult Execute(Func action, Context context, CancellationToken cancellationToken) - { - if (context == null) throw new ArgumentNullException(nameof(context)); - - SetPolicyContext(context, out string priorPolicyWrapKey, out string priorPolicyKey); - - try - { - return Implementation(action, context, cancellationToken); - } - finally - { - RestorePolicyContext(context, priorPolicyWrapKey, priorPolicyKey); - } - } - - #endregion - - #endregion - - #region ExecuteAndCapture overloads - - /// - /// Executes the specified action within the policy and returns the captured result - /// - /// The action to perform. - /// The captured result - [DebuggerStepThrough] - public PolicyResult ExecuteAndCapture(Action action) - => ExecuteAndCapture((ctx, ct) => action(), new Context(), DefaultCancellationToken); - - /// - /// Executes the specified action within the policy and returns the captured result. - /// - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - /// contextData - /// The captured result - [DebuggerStepThrough] - public PolicyResult ExecuteAndCapture(Action action, IDictionary contextData) - => ExecuteAndCapture((ctx, ct) => action(ctx), new Context(contextData), DefaultCancellationToken); - - /// - /// Executes the specified action within the policy and returns the captured result. - /// - /// The action to perform. - /// Context data that is passed to the exception policy. - /// The captured result - [DebuggerStepThrough] - public PolicyResult ExecuteAndCapture(Action action, Context context) - => ExecuteAndCapture((ctx, ct) => action(ctx), context, DefaultCancellationToken); - - /// - /// Executes the specified action within the policy and returns the captured result - /// - /// The action to perform. - /// The cancellation token. - /// The captured result - [DebuggerStepThrough] - public PolicyResult ExecuteAndCapture(Action action, CancellationToken cancellationToken) - => ExecuteAndCapture((ctx, ct) => action(ct), new Context(), cancellationToken); - - /// - /// Executes the specified action within the policy and returns the captured result. - /// - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - /// The cancellation token. - /// The captured result - /// contextData - [DebuggerStepThrough] - public PolicyResult ExecuteAndCapture(Action action, IDictionary contextData, CancellationToken cancellationToken) - => ExecuteAndCapture(action, new Context(contextData), cancellationToken); - - /// - /// Executes the specified action within the policy and returns the captured result - /// - /// The action to perform. - /// Context data that is passed to the exception policy. - /// The cancellation token. - /// The captured result - [DebuggerStepThrough] - public PolicyResult ExecuteAndCapture(Action action, Context context, CancellationToken cancellationToken) - { - if (context == null) throw new ArgumentNullException(nameof(context)); - - try - { - Execute(action, context, cancellationToken); - return PolicyResult.Successful(context); - } - catch (Exception exception) - { - return PolicyResult.Failure(exception, GetExceptionType(ExceptionPredicates, exception), context); - } - } - - #region Overloads method-generic in TResult - - /// - /// Executes the specified action within the policy and returns the captured result - /// - /// The action to perform. - /// The captured result - [DebuggerStepThrough] - public PolicyResult ExecuteAndCapture(Func action) - => ExecuteAndCapture((ctx, ct) => action(), new Context(), DefaultCancellationToken); - - /// - /// Executes the specified action within the policy and returns the captured result. - /// - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - /// contextData - /// The captured result - [DebuggerStepThrough] - public PolicyResult ExecuteAndCapture(Func action, IDictionary contextData) - => ExecuteAndCapture((ctx, ct) => action(ctx), new Context(contextData), DefaultCancellationToken); - - /// - /// Executes the specified action within the policy and returns the captured result. - /// - /// The action to perform. - /// Context data that is passed to the exception policy. - /// contextData - /// The captured result - [DebuggerStepThrough] - public PolicyResult ExecuteAndCapture(Func action, Context context) - => ExecuteAndCapture((ctx, ct) => action(ctx), context, DefaultCancellationToken); - - /// - /// Executes the specified action within the policy and returns the captured result - /// - /// The type of the t result. - /// The action to perform. - /// The cancellation token. - /// The captured result - public PolicyResult ExecuteAndCapture(Func action, CancellationToken cancellationToken) - => ExecuteAndCapture((ctx, ct) => action(ct), new Context(), cancellationToken); - - /// - /// Executes the specified action within the policy and returns the captured result. - /// - /// The type of the result. - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - /// The cancellation token. - /// The captured result - /// contextData - [DebuggerStepThrough] - public PolicyResult ExecuteAndCapture(Func action, IDictionary contextData, CancellationToken cancellationToken) - => ExecuteAndCapture(action, new Context(contextData), cancellationToken); - - /// - /// Executes the specified action within the policy and returns the captured result. - /// - /// The action to perform. - /// Context data that is passed to the exception policy. - /// The cancellation token. - /// The captured result - [DebuggerStepThrough] - public PolicyResult ExecuteAndCapture(Func action, Context context, CancellationToken cancellationToken) - { - if (context == null) throw new ArgumentNullException(nameof(context)); - - try - { - return PolicyResult.Successful(Execute(action, context, cancellationToken), context); - } - catch (Exception exception) - { - return PolicyResult.Failure(exception, GetExceptionType(ExceptionPredicates, exception), context); - } - } - #endregion - - #endregion - - } -} diff --git a/src/Polly/Policy.HandleSyntax.cs b/src/Polly/Policy.HandleSyntax.cs index 8128ca0f497..173b51cefff 100644 --- a/src/Polly/Policy.HandleSyntax.cs +++ b/src/Polly/Policy.HandleSyntax.cs @@ -2,6 +2,9 @@ namespace Polly { + /// + /// Transient exception handling policies that can be applied to synchronous delegates + /// public partial class Policy { @@ -58,6 +61,9 @@ public static PolicyBuilder HandleResult(TResult result) => HandleResult(new Func(r => (r != null && r.Equals(result)) || (r == null && result == null))); } + /// + /// Transient fault handling policies that can be applied to delegates returning results of type + /// public partial class Policy { /// diff --git a/src/Polly/Policy.ISyncPolicy.cs b/src/Polly/Policy.ISyncPolicy.cs new file mode 100644 index 00000000000..9e66674e76a --- /dev/null +++ b/src/Polly/Policy.ISyncPolicy.cs @@ -0,0 +1,525 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading; + +namespace Polly +{ + public abstract partial class Policy : ISyncPolicy + { + #region Execute overloads + + /// + /// Executes the specified synchronous action within the policy. + /// + /// The action to perform. + [DebuggerStepThrough] + public void Execute(Action action) + { + ((ISyncPolicyInternal) this).Execute(new SyncExecutableActionNoParams(action), GetDefaultExecutionContext(), DefaultCancellationToken); + } + + /// + /// Executes the specified synchronous action within the policy. + /// + /// The action to perform. + /// Arbitrary data that is passed to the exception policy. + [DebuggerStepThrough] + public void Execute(Action action, IDictionary contextData) + { + ((ISyncPolicyInternal) this).Execute(new SyncExecutableActionOnContext(action), new Context(contextData), DefaultCancellationToken); + } + + /// + /// Executes the specified synchronous action within the policy. + /// + /// The action to perform. + /// Context data that is passed to the exception policy. + [DebuggerStepThrough] + public void Execute(Action action, Context context) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + ((ISyncPolicyInternal) this).Execute(new SyncExecutableActionOnContext(action), context, DefaultCancellationToken); + } + + /// + /// Executes the specified synchronous action within the policy. + /// + /// The action to perform. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + [DebuggerStepThrough] + public void Execute(Action action, CancellationToken cancellationToken) + { + ((ISyncPolicyInternal) this).Execute(new SyncExecutableActionOnCancellationToken(action), GetDefaultExecutionContext(), cancellationToken); + } + + /// + /// Executes the specified synchronous action within the policy. + /// + /// The action to perform. + /// Arbitrary data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + [DebuggerStepThrough] + public void Execute(Action action, IDictionary contextData, CancellationToken cancellationToken) + { + ((ISyncPolicyInternal) this).Execute(new SyncExecutableAction(action), new Context(contextData), cancellationToken); + } + + /// + /// Executes the specified synchronous action within the policy. + /// + /// The action to perform. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + [DebuggerStepThrough] + public void Execute(Action action, Context context, CancellationToken cancellationToken) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + ((ISyncPolicyInternal) this).Execute(new SyncExecutableAction(action), context, cancellationToken); + } + + /// + /// Executes the specified synchronous action within the policy, passing an extra input of user-defined type . + /// + /// The action to perform. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The type of the first custom input to the function. + [DebuggerStepThrough] + public void Execute(Action action, Context context, CancellationToken cancellationToken, T1 input1) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + ((ISyncPolicyInternal) this).Execute(new SyncExecutableAction(action, input1), context, cancellationToken); + } + + /// + /// Executes the specified synchronous action within the policy, passing two extra inputs of user-defined types and . + /// + /// The action to perform. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The value of the second custom input to the function. + /// The type of the first custom input to the function. + /// The type of the second custom input to the function. + [DebuggerStepThrough] + public void Execute(Action action, Context context, CancellationToken cancellationToken, T1 input1, T2 input2) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + ((ISyncPolicyInternal) this).Execute(new SyncExecutableAction(action, input1, input2), context, cancellationToken); + } + + #region Overloads method-generic in TResult + + /// + /// Executes the specified synchronous action within the policy and returns the result. + /// + /// The type of the result. + /// The action to perform. + /// The value returned by the function + [DebuggerStepThrough] + public TResult Execute(Func func) + { + return ((ISyncPolicyInternal) this).Execute, TResult>( + new SyncExecutableFuncNoParams(func), + GetDefaultExecutionContext(), + DefaultCancellationToken); + } + + /// + /// Executes the specified synchronous action within the policy and returns the result. + /// + /// The action to perform. + /// Arbitrary data that is passed to the exception policy. + /// The value returned by the function + [DebuggerStepThrough] + public TResult Execute(Func func, IDictionary contextData) + { + return ((ISyncPolicyInternal) this).Execute, TResult>( + new SyncExecutableFuncOnContext(func), + new Context(contextData), + DefaultCancellationToken ); + } + + /// + /// Executes the specified synchronous action within the policy and returns the result. + /// + /// The type of the result. + /// The action to perform. + /// Context data that is passed to the exception policy. + /// The value returned by the function + [DebuggerStepThrough] + public TResult Execute(Func func, Context context) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((ISyncPolicyInternal) this).Execute, TResult>( + new SyncExecutableFuncOnContext(func), + context, + DefaultCancellationToken); + } + + /// + /// Executes the specified synchronous action within the policy and returns the result. + /// + /// The type of the result. + /// The action to perform. + /// A cancellation token which can be used to cancel the action. When a retry policy is in use, also cancels any further retries. + /// The value returned by the function + [DebuggerStepThrough] + public TResult Execute(Func func, CancellationToken cancellationToken) + { + return ((ISyncPolicyInternal) this).Execute, TResult>( + new SyncExecutableFuncOnCancellationToken(func), + GetDefaultExecutionContext(), + cancellationToken); + } + + /// + /// Executes the specified synchronous action within the policy and returns the result. + /// + /// The action to perform. + /// Arbitrary data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value returned by the function + [DebuggerStepThrough] + public TResult Execute(Func func, IDictionary contextData, CancellationToken cancellationToken) + { + return ((ISyncPolicyInternal) this).Execute, TResult>( + new SyncExecutableFunc(func), + new Context(contextData), + cancellationToken); + } + + /// + /// Executes the specified synchronous action within the policy and returns the result. + /// + /// The type of the result. + /// The action to perform. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy is in use, also cancels any further retries. + /// The value returned by the function + [DebuggerStepThrough] + public TResult Execute(Func func, Context context, CancellationToken cancellationToken) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((ISyncPolicyInternal) this).Execute, TResult>( + new SyncExecutableFunc(func), + context, + cancellationToken); + } + + /// + /// Executes the specified synchronous function within the policy, passing an extra input of user-defined type , and returns the result. + /// + /// The type of the result. + /// The function to execute. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The type of the first custom input to the function. + /// The value returned by the function + [DebuggerStepThrough] + public TResult Execute(Func func, Context context, CancellationToken cancellationToken, T1 input1) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((ISyncPolicyInternal) this).Execute, TResult>(new SyncExecutableFunc(func, input1), context, cancellationToken); + } + + /// + /// Executes the specified synchronous function within the policy, passing two extra inputs of user-defined types and , and returns the result. + /// + /// The type of the result. + /// The function to execute. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The value of the second custom input to the function. + /// The type of the first custom input to the function. + /// The type of the second custom input to the function. + /// The value returned by the function + [DebuggerStepThrough] + public TResult Execute(Func func, Context context, CancellationToken cancellationToken, T1 input1, T2 input2) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((ISyncPolicyInternal) this).Execute, TResult>(new SyncExecutableFunc(func, input1, input2), context, cancellationToken); + } + + #endregion + + #endregion + + #region ExecuteAndCapture overloads + + /// + /// Executes the specified synchronous action within the policy and returns the captured result. + /// + /// The action to perform. + /// The outcome of the execution, as a captured + [DebuggerStepThrough] + public PolicyResult ExecuteAndCapture(Action action) + { + return ((ISyncPolicyInternal) this).ExecuteAndCapture(new SyncExecutableActionNoParams(action), GetDefaultExecutionContext(), DefaultCancellationToken); + } + + /// + /// Executes the specified synchronous action within the policy and returns the captured result. + /// + /// The action to perform. + /// Arbitrary data that is passed to the exception policy. + /// contextData + /// The outcome of the execution, as a captured + [DebuggerStepThrough] + public PolicyResult ExecuteAndCapture(Action action, IDictionary contextData) + { + return ((ISyncPolicyInternal) this).ExecuteAndCapture(new SyncExecutableActionOnContext(action), new Context(contextData), DefaultCancellationToken); + } + + /// + /// Executes the specified synchronous action within the policy and returns the captured result. + /// + /// The action to perform. + /// Context data that is passed to the exception policy. + /// The outcome of the execution, as a captured + [DebuggerStepThrough] + public PolicyResult ExecuteAndCapture(Action action, Context context) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((ISyncPolicyInternal) this).ExecuteAndCapture(new SyncExecutableActionOnContext(action), context, DefaultCancellationToken); + } + + /// + /// Executes the specified synchronous action within the policy and returns the captured result. + /// + /// The action to perform. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The outcome of the execution, as a captured + [DebuggerStepThrough] + public PolicyResult ExecuteAndCapture(Action action, CancellationToken cancellationToken) + { + return ((ISyncPolicyInternal) this).ExecuteAndCapture(new SyncExecutableActionOnCancellationToken(action), GetDefaultExecutionContext(), cancellationToken); + } + + /// + /// Executes the specified synchronous action within the policy and returns the captured result. + /// + /// The action to perform. + /// Arbitrary data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// contextData + /// The outcome of the execution, as a captured + [DebuggerStepThrough] + public PolicyResult ExecuteAndCapture(Action action, IDictionary contextData, CancellationToken cancellationToken) + { + return ((ISyncPolicyInternal) this).ExecuteAndCapture(new SyncExecutableAction(action), new Context(contextData), cancellationToken); + } + + /// + /// Executes the specified synchronous action within the policy and returns the captured result. + /// + /// The action to perform. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The outcome of the execution, as a captured + [DebuggerStepThrough] + public PolicyResult ExecuteAndCapture(Action action, Context context, CancellationToken cancellationToken) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((ISyncPolicyInternal) this).ExecuteAndCapture(new SyncExecutableAction(action), context, cancellationToken); + } + + /// + /// Executes the specified synchronous action within the policy, passing an extra input of user-defined type . + /// + /// The action to perform. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The type of the first custom input to the function. + /// The outcome of the execution, as a captured + [DebuggerStepThrough] + public PolicyResult ExecuteAndCapture(Action action, Context context, CancellationToken cancellationToken, T1 input1) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((ISyncPolicyInternal) this).ExecuteAndCapture(new SyncExecutableAction(action, input1), context, cancellationToken); + } + + /// + /// Executes the specified synchronous action within the policy, passing two extra inputs of user-defined types and . + /// + /// The action to perform. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The value of the second custom input to the function. + /// The type of the first custom input to the function. + /// The type of the second custom input to the function. + /// The outcome of the execution, as a captured + [DebuggerStepThrough] + public PolicyResult ExecuteAndCapture(Action action, Context context, CancellationToken cancellationToken, T1 input1, T2 input2) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((ISyncPolicyInternal) this).ExecuteAndCapture(new SyncExecutableAction(action, input1, input2), context, cancellationToken); + } + + #region Overloads method-generic in TResult + + /// + /// Executes the specified synchronous function within the policy and returns the result. + /// + /// The type of the result. + /// The function to invoke. + /// The outcome of the execution, as a captured + [DebuggerStepThrough] + public PolicyResult ExecuteAndCapture(Func func) + { + return ((ISyncPolicyInternal) this).ExecuteAndCapture, TResult>( + new SyncExecutableFuncNoParams(func), + GetDefaultExecutionContext(), + DefaultCancellationToken); + } + + /// + /// Executes the specified synchronous function within the policy and returns the result. + /// + /// The type of the result. + /// The function to invoke. + /// Arbitrary data that is passed to the exception policy. + /// contextData + /// The outcome of the execution, as a captured + [DebuggerStepThrough] + public PolicyResult ExecuteAndCapture(Func func, IDictionary contextData) + { + return ((ISyncPolicyInternal) this).ExecuteAndCapture, TResult>( + new SyncExecutableFuncOnContext(func), + new Context(contextData), + DefaultCancellationToken); + } + + /// + /// Executes the specified synchronous function within the policy and returns the result. + /// + /// The type of the result. + /// The function to invoke. + /// Context data that is passed to the exception policy. + /// The outcome of the execution, as a captured + [DebuggerStepThrough] + public PolicyResult ExecuteAndCapture(Func func, Context context) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((ISyncPolicyInternal) this).ExecuteAndCapture, TResult>( + new SyncExecutableFuncOnContext(func), + context, + DefaultCancellationToken); + } + + /// + /// Executes the specified synchronous function within the policy and returns the result. + /// + /// The type of the result. + /// The function to invoke. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The outcome of the execution, as a captured + [DebuggerStepThrough] + public PolicyResult ExecuteAndCapture(Func func, CancellationToken cancellationToken) + { + return ((ISyncPolicyInternal) this).ExecuteAndCapture, TResult>( + new SyncExecutableFuncOnCancellationToken(func), + GetDefaultExecutionContext(), + cancellationToken); + } + + /// + /// Executes the specified synchronous function within the policy and returns the result. + /// + /// The type of the result. + /// The function to invoke. + /// Arbitrary data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// contextData + /// The outcome of the execution, as a captured + [DebuggerStepThrough] + public PolicyResult ExecuteAndCapture(Func func, IDictionary contextData, CancellationToken cancellationToken) + { + return ((ISyncPolicyInternal) this).ExecuteAndCapture, TResult>( + new SyncExecutableFunc(func), + new Context(contextData), + cancellationToken); + } + + /// + /// Executes the specified synchronous function within the policy and returns the result. + /// + /// The type of the result. + /// The function to invoke. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The outcome of the execution, as a captured + [DebuggerStepThrough] + public PolicyResult ExecuteAndCapture(Func func, Context context, CancellationToken cancellationToken) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((ISyncPolicyInternal) this).ExecuteAndCapture, TResult>( + new SyncExecutableFunc(func), + context, + cancellationToken); + } + + /// + /// Executes the specified synchronous function within the policy, passing an extra input of user-defined type , and returns the captured result. + /// + /// The type of the result. + /// The function to execute. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The type of the first custom input to the function. + /// The outcome of the execution, as a captured + [DebuggerStepThrough] + public PolicyResult ExecuteAndCapture(Func func, Context context, CancellationToken cancellationToken, T1 input1) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((ISyncPolicyInternal) this).ExecuteAndCapture, TResult>(new SyncExecutableFunc(func, input1), context, cancellationToken); + } + + /// + /// Executes the specified synchronous function within the policy, passing two extra inputs of user-defined types and , and returns the result. + /// + /// The type of the result. + /// The function to execute. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The value of the second custom input to the function. + /// The type of the first custom input to the function. + /// The type of the second custom input to the function. + /// The outcome of the execution, as a captured + [DebuggerStepThrough] + public PolicyResult ExecuteAndCapture(Func func, Context context, CancellationToken cancellationToken, T1 input1, T2 input2) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((ISyncPolicyInternal) this).ExecuteAndCapture, TResult>(new SyncExecutableFunc(func, input1, input2), context, cancellationToken); + } + + #endregion + + #endregion + + } +} diff --git a/src/Polly/Policy.ISyncPolicyInternal.cs b/src/Polly/Policy.ISyncPolicyInternal.cs new file mode 100644 index 00000000000..0877935b74b --- /dev/null +++ b/src/Polly/Policy.ISyncPolicyInternal.cs @@ -0,0 +1,75 @@ +using System; +using System.Diagnostics; +using System.Threading; + +namespace Polly +{ + public abstract partial class Policy : ISyncPolicyInternal + { + [DebuggerStepThrough] + void ISyncPolicyInternal.Execute(in TExecutable action, Context context, CancellationToken cancellationToken) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + SetPolicyContext(context, out string priorPolicyWrapKey, out string priorPolicyKey); + + try + { + SyncNonGenericImplementation(action, context, cancellationToken); + } + finally + { + RestorePolicyContext(context, priorPolicyWrapKey, priorPolicyKey); + } + } + + [DebuggerStepThrough] + TResult ISyncPolicyInternal.Execute(in TExecutable action, Context context, CancellationToken cancellationToken) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + SetPolicyContext(context, out string priorPolicyWrapKey, out string priorPolicyKey); + + try + { + return SyncGenericImplementation(action, context, cancellationToken); + } + finally + { + RestorePolicyContext(context, priorPolicyWrapKey, priorPolicyKey); + } + } + + [DebuggerStepThrough] + PolicyResult ISyncPolicyInternal.ExecuteAndCapture(in TExecutable action, Context context, CancellationToken cancellationToken) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + try + { + ((ISyncPolicyInternal) this).Execute(action, context, cancellationToken); + return PolicyResult.Successful(context); + } + catch (Exception exception) + { + return PolicyResult.Failure(exception, GetExceptionType(ExceptionPredicates, exception), context); + } + } + + [DebuggerStepThrough] + PolicyResult ISyncPolicyInternal.ExecuteAndCapture(in TExecutable action, Context context, CancellationToken cancellationToken) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + try + { + return PolicyResult.Successful(((ISyncPolicyInternal) this).Execute(action, context, cancellationToken), + context); + } + catch (Exception exception) + { + return PolicyResult.Failure(exception, GetExceptionType(ExceptionPredicates, exception), context); + } + } + } +} diff --git a/src/Polly/Policy.SyncNonGenericImplementation.cs b/src/Polly/Policy.Implementation.cs similarity index 53% rename from src/Polly/Policy.SyncNonGenericImplementation.cs rename to src/Polly/Policy.Implementation.cs index 60a1c46522e..616d4473c09 100644 --- a/src/Polly/Policy.SyncNonGenericImplementation.cs +++ b/src/Polly/Policy.Implementation.cs @@ -1,7 +1,4 @@ -using System; -using System.Diagnostics; -using System.Threading; -using Polly.Utilities; +using System.Threading; namespace Polly { @@ -13,18 +10,26 @@ public abstract partial class Policy /// The action passed by calling code to execute through the policy. /// The policy execution context. /// A token to signal that execution should be cancelled. - [DebuggerStepThrough] - protected virtual void Implementation(Action action, Context context, CancellationToken cancellationToken) - => Implementation((ctx, token) => { action(ctx, token); return EmptyStruct.Instance; }, context, cancellationToken); + protected virtual void SyncNonGenericImplementation( + in TExecutable action, + Context context, + CancellationToken cancellationToken) + where TExecutable : ISyncExecutable + { + SyncGenericImplementation(action, context, cancellationToken); + } /// - /// Defines the implementation of a policy for synchronous executions returning . + /// Defines the implementation of a policy for sync executions returning . /// - /// The type returned by synchronous executions through the implementation. /// The action passed by calling code to execute through the policy. /// The policy execution context. /// A token to signal that execution should be cancelled. /// A result of the execution. - protected abstract TResult Implementation(Func action, Context context, CancellationToken cancellationToken); + protected abstract TResult SyncGenericImplementation( + in TExecutable action, + Context context, + CancellationToken cancellationToken) + where TExecutable : ISyncExecutable; } } diff --git a/src/Polly/Policy.ContextAndKeys.cs b/src/Polly/Policy.PolicyKeys.cs similarity index 97% rename from src/Polly/Policy.ContextAndKeys.cs rename to src/Polly/Policy.PolicyKeys.cs index f9a7c7c1b15..075c3acf751 100644 --- a/src/Polly/Policy.ContextAndKeys.cs +++ b/src/Polly/Policy.PolicyKeys.cs @@ -21,7 +21,7 @@ public Policy WithPolicyKey(String policyKey) /// Sets the PolicyKey for this instance. /// Must be called before the policy is first used. Can only be set once. /// - /// The unique, used-definable key to assign to this instance. + /// The unique, used-definable key to assign to this instance. ISyncPolicy ISyncPolicy.WithPolicyKey(String policyKey) { if (policyKeyInternal != null) throw PolicyKeyMustBeImmutableException; diff --git a/src/Polly/Policy.TResult.ExecuteOverloads.cs b/src/Polly/Policy.TResult.ExecuteOverloads.cs deleted file mode 100644 index a2472ddc94c..00000000000 --- a/src/Polly/Policy.TResult.ExecuteOverloads.cs +++ /dev/null @@ -1,185 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Threading; - - -namespace Polly -{ - public abstract partial class Policy : ISyncPolicy - { - - #region Execute overloads - - /// - /// Executes the specified action within the policy and returns the Result. - /// - /// The action to perform. - /// The value returned by the action - [DebuggerStepThrough] - public TResult Execute(Func action) - => Execute((ctx, ct) => action(), new Context(), DefaultCancellationToken); - - /// - /// Executes the specified action within the policy and returns the result. - /// - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - /// contextData - /// - /// The value returned by the action - /// - /// contextData - [DebuggerStepThrough] - public TResult Execute(Func action, IDictionary contextData) - => Execute((ctx, ct) => action(ctx), new Context(contextData), DefaultCancellationToken); - - /// - /// Executes the specified action within the policy and returns the result. - /// - /// The action to perform. - /// Context data that is passed to the exception policy. - /// context - /// - /// The value returned by the action - /// - /// contextData - [DebuggerStepThrough] - public TResult Execute(Func action, Context context) - => Execute((ctx, ct) => action(ctx), context, DefaultCancellationToken); - - /// - /// Executes the specified action within the policy and returns the result. - /// - /// The action to perform. - /// The cancellation token. - /// The value returned by the action - [DebuggerStepThrough] - public TResult Execute(Func action, CancellationToken cancellationToken) - => Execute((ctx, ct) => action(ct), new Context(), cancellationToken); - - /// - /// Executes the specified action within the policy and returns the result. - /// - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - /// The cancellation token. - /// The value returned by the action - /// contextData - [DebuggerStepThrough] - public TResult Execute(Func action, IDictionary contextData, CancellationToken cancellationToken) - => Execute(action, new Context(contextData), cancellationToken); - - /// - /// Executes the specified action within the policy and returns the result. - /// - /// The action to perform. - /// Context data that is passed to the exception policy. - /// The cancellation token. - /// The value returned by the action - [DebuggerStepThrough] - public TResult Execute(Func action, Context context, CancellationToken cancellationToken) - { - if (context == null) throw new ArgumentNullException(nameof(context)); - - SetPolicyContext(context, out string priorPolicyWrapKey, out string priorPolicyKey); - - try - { - return Implementation(action, context, cancellationToken); - } - finally - { - RestorePolicyContext(context, priorPolicyWrapKey, priorPolicyKey); - } - } - - #endregion - - #region ExecuteAndCapture overloads - - /// - /// Executes the specified action within the policy and returns the captured result - /// - /// The action to perform. - /// The captured result - [DebuggerStepThrough] - public PolicyResult ExecuteAndCapture(Func action) - => ExecuteAndCapture((ctx, ct) => action(), new Context(), DefaultCancellationToken); - - /// - /// Executes the specified action within the policy and returns the captured result. - /// - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - /// contextData - /// The captured result - [DebuggerStepThrough] - public PolicyResult ExecuteAndCapture(Func action, IDictionary contextData) - => ExecuteAndCapture((ctx, ct) => action(ctx), new Context(contextData), DefaultCancellationToken); - - /// - /// Executes the specified action within the policy and returns the captured result. - /// - /// The action to perform. - /// Context data that is passed to the exception policy. - /// contextData - /// The captured result - [DebuggerStepThrough] - public PolicyResult ExecuteAndCapture(Func action, Context context) - => ExecuteAndCapture((ctx, ct) => action(ctx), context, DefaultCancellationToken); - - /// - /// Executes the specified action within the policy and returns the captured result - /// - /// The action to perform. - /// The cancellation token. - /// The captured result - [DebuggerStepThrough] - public PolicyResult ExecuteAndCapture(Func action, CancellationToken cancellationToken) - => ExecuteAndCapture((ctx, ct) => action(ct), new Context(), cancellationToken); - - /// - /// Executes the specified action within the policy and returns the captured result. - /// - /// The action to perform. - /// Arbitrary data that is passed to the exception policy. - /// The cancellation token. - /// The captured result - /// contextData - [DebuggerStepThrough] - public PolicyResult ExecuteAndCapture(Func action, IDictionary contextData, CancellationToken cancellationToken) - => ExecuteAndCapture(action, new Context(contextData), cancellationToken); - - /// - /// Executes the specified action within the policy and returns the captured result. - /// - /// The action to perform. - /// Context data that is passed to the exception policy. - /// The cancellation token. - /// The captured result - [DebuggerStepThrough] - public PolicyResult ExecuteAndCapture(Func action, Context context, CancellationToken cancellationToken) - { - if (context == null) throw new ArgumentNullException(nameof(context)); - - try - { - TResult result = Execute(action, context, cancellationToken); - - if (ResultPredicates.AnyMatch(result)) - { - return PolicyResult.Failure(result, context); - } - - return PolicyResult.Successful(result, context); - } - catch (Exception exception) - { - return PolicyResult.Failure(exception, GetExceptionType(ExceptionPredicates, exception), context); - } - } - - #endregion - } -} diff --git a/src/Polly/Policy.TResult.ISyncPolicy.cs b/src/Polly/Policy.TResult.ISyncPolicy.cs new file mode 100644 index 00000000000..3c177270f9b --- /dev/null +++ b/src/Polly/Policy.TResult.ISyncPolicy.cs @@ -0,0 +1,283 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading; + +namespace Polly +{ + public abstract partial class Policy : ISyncPolicy + { + #region Execute overloads + + /// + /// Executes the specified synchronous function within the policy and returns the result. + /// + /// The function to invoke. + /// The value returned by the function + [DebuggerStepThrough] + public TResult Execute(Func func) + { + return ((ISyncPolicyInternal)this).Execute( + new SyncExecutableFuncNoParams(func), + GetDefaultExecutionContext(), + DefaultCancellationToken); + } + + /// + /// Executes the specified synchronous function within the policy and returns the result. + /// + /// The function to invoke. + /// Arbitrary data that is passed to the exception policy. + /// The value returned by the function + [DebuggerStepThrough] + public TResult Execute(Func func, IDictionary contextData) + { + return ((ISyncPolicyInternal)this).Execute( + new SyncExecutableFuncOnContext(func), + new Context(contextData), + DefaultCancellationToken); + } + + /// + /// Executes the specified synchronous function within the policy and returns the result. + /// + /// The function to invoke. + /// Context data that is passed to the exception policy. + /// The value returned by the function + [DebuggerStepThrough] + public TResult Execute(Func func, Context context) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((ISyncPolicyInternal)this).Execute( + new SyncExecutableFuncOnContext(func), + context, + DefaultCancellationToken); + } + + /// + /// Executes the specified synchronous function within the policy and returns the result. + /// + /// The function to invoke. + /// A cancellation token which can be used to cancel the action. When a retry policy is in use, also cancels any further retries. + /// The value returned by the function + [DebuggerStepThrough] + public TResult Execute(Func func, CancellationToken cancellationToken) + { + return ((ISyncPolicyInternal)this).Execute( + new SyncExecutableFuncOnCancellationToken(func), + GetDefaultExecutionContext(), + cancellationToken); + } + + /// + /// Executes the specified synchronous function within the policy and returns the result. + /// + /// The function to invoke. + /// Arbitrary data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value returned by the function + /// contextData + [DebuggerStepThrough] + public TResult Execute(Func func, IDictionary contextData, CancellationToken cancellationToken) + { + return ((ISyncPolicyInternal)this).Execute( + new SyncExecutableFunc(func), + new Context(contextData), + cancellationToken); + } + + /// + /// Executes the specified synchronous function within the policy and returns the result. + /// + /// The function to execute. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy is in use, also cancels any further retries. + /// The value returned by the function + [DebuggerStepThrough] + public TResult Execute(Func func, Context context, CancellationToken cancellationToken) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((ISyncPolicyInternal)this).Execute( + new SyncExecutableFunc(func), + context, + cancellationToken); + } + + /// + /// Executes the specified synchronous function within the policy, passing an extra input of user-defined type , and returns the result. + /// + /// The function to execute. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The type of the first custom input to the function. + /// The value returned by the function + [DebuggerStepThrough] + public TResult Execute(Func func, Context context, CancellationToken cancellationToken, T1 input1) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((ISyncPolicyInternal)this).Execute(new SyncExecutableFunc(func, input1), context, cancellationToken); + } + + /// + /// Executes the specified synchronous function within the policy, passing two extra inputs of user-defined types and , and returns the result. + /// + /// The function to execute. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The value of the second custom input to the function. + /// The type of the first custom input to the function. + /// The type of the second custom input to the function. + /// The value returned by the function + [DebuggerStepThrough] + public TResult Execute(Func func, Context context, CancellationToken cancellationToken, T1 input1, T2 input2) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((ISyncPolicyInternal)this).Execute(new SyncExecutableFunc(func, input1, input2), context, cancellationToken); + } + + #endregion + + #region ExecuteAndCapture overloads + + /// + /// Executes the specified synchronous action within the policy and returns the result. + /// + /// The function to invoke. + /// The outcome of the execution, as a captured + [DebuggerStepThrough] + public PolicyResult ExecuteAndCapture(Func func) + { + return ((ISyncPolicyInternal)this).ExecuteAndCapture( + new SyncExecutableFuncNoParams(func), + GetDefaultExecutionContext(), + DefaultCancellationToken); + } + + /// + /// Executes the specified synchronous action within the policy and returns the result. + /// + /// The function to invoke. + /// Arbitrary data that is passed to the exception policy. + /// contextData + /// The outcome of the execution, as a captured + [DebuggerStepThrough] + public PolicyResult ExecuteAndCapture(Func func, IDictionary contextData) + { + return ((ISyncPolicyInternal)this).ExecuteAndCapture( + new SyncExecutableFuncOnContext(func), + new Context(contextData), + DefaultCancellationToken); + } + + /// + /// Executes the specified synchronous action within the policy and returns the result. + /// + /// The function to invoke. + /// Context data that is passed to the exception policy. + /// The outcome of the execution, as a captured + [DebuggerStepThrough] + public PolicyResult ExecuteAndCapture(Func func, Context context) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((ISyncPolicyInternal)this).ExecuteAndCapture( + new SyncExecutableFuncOnContext(func), + context, + DefaultCancellationToken); + } + + /// + /// Executes the specified synchronous action within the policy and returns the result. + /// + /// The function to invoke. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The outcome of the execution, as a captured + [DebuggerStepThrough] + public PolicyResult ExecuteAndCapture(Func func, CancellationToken cancellationToken) + { + return ((ISyncPolicyInternal)this).ExecuteAndCapture( + new SyncExecutableFuncOnCancellationToken(func), + GetDefaultExecutionContext(), + cancellationToken); + } + + /// + /// Executes the specified synchronous action within the policy and returns the result. + /// + /// The function to invoke. + /// Arbitrary data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// contextData + /// The outcome of the execution, as a captured + [DebuggerStepThrough] + public PolicyResult ExecuteAndCapture(Func func, IDictionary contextData, CancellationToken cancellationToken) + { + return ((ISyncPolicyInternal)this).ExecuteAndCapture( + new SyncExecutableFunc(func), + new Context(contextData), + cancellationToken); + } + + /// + /// Executes the specified synchronous action within the policy and returns the result. + /// + /// The function to invoke. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The outcome of the execution, as a captured + [DebuggerStepThrough] + public PolicyResult ExecuteAndCapture(Func func, Context context, CancellationToken cancellationToken) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((ISyncPolicyInternal)this).ExecuteAndCapture( + new SyncExecutableFunc(func), + context, + cancellationToken); + } + + /// + /// Executes the specified synchronous function within the policy, passing an extra input of user-defined type , and returns the captured result. + /// + /// The function to execute. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The type of the first custom input to the function. + /// The outcome of the execution, as a captured + [DebuggerStepThrough] + public PolicyResult ExecuteAndCapture(Func func, Context context, CancellationToken cancellationToken, T1 input1) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((ISyncPolicyInternal)this).ExecuteAndCapture(new SyncExecutableFunc(func, input1), context, cancellationToken); + } + + /// + /// Executes the specified synchronous function within the policy, passing two extra inputs of user-defined types and , and returns the result. + /// + /// The function to execute. + /// Context data that is passed to the exception policy. + /// A cancellation token which can be used to cancel the action. When a retry policy in use, also cancels any further retries. + /// The value of the first custom input to the function. + /// The value of the second custom input to the function. + /// The type of the first custom input to the function. + /// The type of the second custom input to the function. + /// The outcome of the execution, as a captured + [DebuggerStepThrough] + public PolicyResult ExecuteAndCapture(Func func, Context context, CancellationToken cancellationToken, T1 input1, T2 input2) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + return ((ISyncPolicyInternal)this).ExecuteAndCapture(new SyncExecutableFunc(func, input1, input2), context, cancellationToken); + } + + #endregion + } +} diff --git a/src/Polly/Policy.TResult.ISyncPolicyInternal.cs b/src/Polly/Policy.TResult.ISyncPolicyInternal.cs new file mode 100644 index 00000000000..a5af38c77fd --- /dev/null +++ b/src/Polly/Policy.TResult.ISyncPolicyInternal.cs @@ -0,0 +1,48 @@ +using System; +using System.Diagnostics; +using System.Threading; + +namespace Polly +{ + public abstract partial class Policy : ISyncPolicyInternal + { + [DebuggerStepThrough] + TResult ISyncPolicyInternal.Execute(in TExecutable action, Context context, CancellationToken cancellationToken) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + SetPolicyContext(context, out string priorPolicyWrapKey, out string priorPolicyKey); + + try + { + return SyncGenericImplementation(action, context, cancellationToken); + } + finally + { + RestorePolicyContext(context, priorPolicyWrapKey, priorPolicyKey); + } + } + + [DebuggerStepThrough] + PolicyResult ISyncPolicyInternal.ExecuteAndCapture(in TExecutable action, Context context, CancellationToken cancellationToken) + { + if (context == null) throw new ArgumentNullException(nameof(context)); + + try + { + TResult result = ((ISyncPolicyInternal)this).Execute(action, context, cancellationToken); + + if (ResultPredicates.AnyMatch(result)) + { + return PolicyResult.Failure(result, context); + } + + return PolicyResult.Successful(result, context); + } + catch (Exception exception) + { + return PolicyResult.Failure(exception, GetExceptionType(ExceptionPredicates, exception), context); + } + } + } +} diff --git a/src/Polly/Policy.SyncGenericImplementation.cs b/src/Polly/Policy.TResult.Implementation.cs similarity index 52% rename from src/Polly/Policy.SyncGenericImplementation.cs rename to src/Polly/Policy.TResult.Implementation.cs index e02cdaf18ad..bc42d2e72e7 100644 --- a/src/Polly/Policy.SyncGenericImplementation.cs +++ b/src/Polly/Policy.TResult.Implementation.cs @@ -1,21 +1,23 @@ -using System; -using System.Threading; +using System.Threading; namespace Polly { + /// + /// Transient exception handling policies that can be applied to synchronous delegates + /// public abstract partial class Policy { /// - /// Defines the implementation of a policy for synchronous executions returning . + /// Defines the implementation of a policy for async executions returning . /// /// The action passed by calling code to execute through the policy. /// The policy execution context. /// A token to signal that execution should be cancelled. /// A result of the execution. - protected abstract TResult Implementation( - Func action, + protected abstract TResult SyncGenericImplementation( + in TExecutable action, Context context, - CancellationToken cancellationToken - ); + CancellationToken cancellationToken) + where TExecutable : ISyncExecutable; } -} +} \ No newline at end of file diff --git a/src/Polly/PolicyBase.ContextAndKeys.cs b/src/Polly/PolicyBase.ContextAndKeys.cs index 828e3e6b7fc..159ade8c2e5 100644 --- a/src/Polly/PolicyBase.ContextAndKeys.cs +++ b/src/Polly/PolicyBase.ContextAndKeys.cs @@ -13,7 +13,7 @@ public abstract partial class PolicyBase /// /// A key intended to be unique to each instance, which is passed with executions as the property. /// - public String PolicyKey => policyKeyInternal ?? (policyKeyInternal = GetType().Name + "-" + KeyHelper.GuidPart()); + public String PolicyKey => policyKeyInternal ??= $"{GetType().Name}-{KeyHelper.GuidPart()}"; internal static ArgumentException PolicyKeyMustBeImmutableException => new ArgumentException("PolicyKey cannot be changed once set; or (when using the default value after the PolicyKey property has been accessed.", "policyKey"); diff --git a/src/Polly/PolicyBase.cs b/src/Polly/PolicyBase.cs index 689a5be3fad..1637a2415cd 100644 --- a/src/Polly/PolicyBase.cs +++ b/src/Polly/PolicyBase.cs @@ -6,12 +6,16 @@ namespace Polly /// /// Implements elements common to both non-generic and generic policies, and sync and async policies. /// - public abstract partial class PolicyBase + public abstract partial class PolicyBase : IExceptionPredicates { /// /// Predicates indicating which exceptions the policy handles. /// - protected internal ExceptionPredicates ExceptionPredicates { get; } + protected ExceptionPredicates ExceptionPredicates { get; } + + ExceptionPredicates IExceptionPredicates.PredicatesInternal => ExceptionPredicates; + + internal Context GetDefaultExecutionContext() => new Context(); /// /// Defines a CancellationToken to use, when none is supplied. @@ -52,12 +56,14 @@ protected PolicyBase(PolicyBuilder policyBuilder) /// /// Implements elements common to sync and async generic policies. /// - public abstract class PolicyBase : PolicyBase + public abstract class PolicyBase : PolicyBase, IResultPredicates { /// /// Predicates indicating which results the policy handles. /// - protected internal ResultPredicates ResultPredicates { get; } + protected ResultPredicates ResultPredicates { get; } + + ResultPredicates IResultPredicates.PredicatesInternal => ResultPredicates; /// /// Constructs a new instance of a derived type of . diff --git a/src/Polly/PolicyBuilder.OrSyntax.cs b/src/Polly/PolicyBuilder.OrSyntax.cs index 91737f86523..d6051727050 100644 --- a/src/Polly/PolicyBuilder.OrSyntax.cs +++ b/src/Polly/PolicyBuilder.OrSyntax.cs @@ -110,8 +110,7 @@ public partial class PolicyBuilder /// The PolicyBuilder instance. public PolicyBuilder OrResult(Func resultPredicate) { - ResultPredicate predicate = result => resultPredicate(result); - ResultPredicates.Add(predicate); + ResultPredicates.Add(result => resultPredicate(result)); return this; } diff --git a/src/Polly/Polly.csproj b/src/Polly/Polly.csproj index 1cf5658646d..dc378fc222b 100644 --- a/src/Polly/Polly.csproj +++ b/src/Polly/Polly.csproj @@ -2,6 +2,7 @@ netstandard1.1;netstandard2.0;net461;net472 + 8.0 Polly Polly 7.1.1 diff --git a/src/Polly/ResultPredicates.cs b/src/Polly/ResultPredicates.cs index 1593148bac1..635f44f51f8 100644 --- a/src/Polly/ResultPredicates.cs +++ b/src/Polly/ResultPredicates.cs @@ -12,7 +12,7 @@ public class ResultPredicates internal void Add(ResultPredicate predicate) { - _predicates = _predicates ?? new List>(); // The ?? pattern here is sufficient; only a deliberately contrived example would lead to the same PolicyBuilder instance being used in a multi-threaded way to define policies simultaneously on multiple threads. + _predicates ??= new List>(); // The ?? pattern here is sufficient; only a deliberately contrived example would lead to the same PolicyBuilder instance being used in a multi-threaded way to define policies simultaneously on multiple threads. _predicates.Add(predicate); } diff --git a/src/Polly/Retry/AsyncRetryEngine.cs b/src/Polly/Retry/AsyncRetryEngine.cs index 152402140c4..f0d25094873 100644 --- a/src/Polly/Retry/AsyncRetryEngine.cs +++ b/src/Polly/Retry/AsyncRetryEngine.cs @@ -8,8 +8,8 @@ namespace Polly.Retry { internal static class AsyncRetryEngine { - internal static async Task ImplementationAsync( - Func> action, + internal static async Task ImplementationAsync( + TExecutableAsync action, Context context, CancellationToken cancellationToken, ExceptionPredicates shouldRetryExceptionPredicates, @@ -19,6 +19,7 @@ internal static async Task ImplementationAsync( IEnumerable sleepDurationsEnumerable = null, Func, Context, TimeSpan> sleepDurationProvider = null, bool continueOnCapturedContext = false) + where TExecutableAsync : IAsyncExecutable { int tryCount = 0; IEnumerator sleepDurationsEnumerator = sleepDurationsEnumerable?.GetEnumerator(); @@ -34,7 +35,7 @@ internal static async Task ImplementationAsync( try { - TResult result = await action(context, cancellationToken).ConfigureAwait(continueOnCapturedContext); + TResult result = await action.ExecuteAsync(context, cancellationToken, continueOnCapturedContext).ConfigureAwait(continueOnCapturedContext); if (!shouldRetryResultPredicates.AnyMatch(result)) { diff --git a/src/Polly/Retry/AsyncRetryPolicy.cs b/src/Polly/Retry/AsyncRetryPolicy.cs index f8969b8a777..029fa8eda39 100644 --- a/src/Polly/Retry/AsyncRetryPolicy.cs +++ b/src/Polly/Retry/AsyncRetryPolicy.cs @@ -33,7 +33,7 @@ internal AsyncRetryPolicy( /// [DebuggerStepThrough] - protected override Task ImplementationAsync(Func> action, Context context, CancellationToken cancellationToken, + protected override Task AsyncGenericImplementation(TExecutableAsync action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) { return AsyncRetryEngine.ImplementationAsync( @@ -81,7 +81,7 @@ internal AsyncRetryPolicy( /// [DebuggerStepThrough] - protected override Task ImplementationAsync(Func> action, Context context, CancellationToken cancellationToken, + protected override Task AsyncGenericImplementation(TExecutableAsync action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) => AsyncRetryEngine.ImplementationAsync( action, diff --git a/src/Polly/Retry/RetryEngine.cs b/src/Polly/Retry/RetryEngine.cs index ff3dad0fc3e..afc10b5c8f6 100644 --- a/src/Polly/Retry/RetryEngine.cs +++ b/src/Polly/Retry/RetryEngine.cs @@ -7,8 +7,8 @@ namespace Polly.Retry { internal static class RetryEngine { - internal static TResult Implementation( - Func action, + internal static TResult Implementation( + in TExecutable action, Context context, CancellationToken cancellationToken, ExceptionPredicates shouldRetryExceptionPredicates, @@ -17,6 +17,7 @@ internal static TResult Implementation( int permittedRetryCount = Int32.MaxValue, IEnumerable sleepDurationsEnumerable = null, Func, Context, TimeSpan> sleepDurationProvider = null) + where TExecutable : ISyncExecutable { int tryCount = 0; IEnumerator sleepDurationsEnumerator = sleepDurationsEnumerable?.GetEnumerator(); @@ -32,7 +33,7 @@ internal static TResult Implementation( try { - TResult result = action(context, cancellationToken); + TResult result = action.Execute(context, cancellationToken); if (!shouldRetryResultPredicates.AnyMatch(result)) { diff --git a/src/Polly/Retry/RetryPolicy.cs b/src/Polly/Retry/RetryPolicy.cs index a7748521d97..cd0ccdee511 100644 --- a/src/Polly/Retry/RetryPolicy.cs +++ b/src/Polly/Retry/RetryPolicy.cs @@ -31,7 +31,7 @@ internal RetryPolicy( } /// - protected override TResult Implementation(Func action, + protected override TResult SyncGenericImplementation(in TExecutable action, Context context, CancellationToken cancellationToken) => RetryEngine.Implementation( action, @@ -76,7 +76,7 @@ internal RetryPolicy( /// [DebuggerStepThrough] - protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken) + protected override TResult SyncGenericImplementation(in TExecutable action, Context context, CancellationToken cancellationToken) => RetryEngine.Implementation( action, context, diff --git a/src/Polly/SyncExecutables.cs b/src/Polly/SyncExecutables.cs new file mode 100644 index 00000000000..231184b05a5 --- /dev/null +++ b/src/Polly/SyncExecutables.cs @@ -0,0 +1,221 @@ +using System; +using System.Threading; + +namespace Polly +{ + /// + internal readonly struct SyncExecutableActionNoParams : ISyncExecutable + { + private readonly Action _action; + + public SyncExecutableActionNoParams(Action action) + { + _action = action; + } + + /// + public readonly object Execute(Context context, CancellationToken cancellationToken) + { + _action(); + return null; + } + } + + /// + internal readonly struct SyncExecutableActionOnContext : ISyncExecutable + { + private readonly Action _action; + + public SyncExecutableActionOnContext(Action action) + { + _action = action; + } + + /// + public readonly object Execute(Context context, CancellationToken cancellationToken) + { + _action(context); + return null; + } + } + + /// + internal readonly struct SyncExecutableActionOnCancellationToken : ISyncExecutable + { + private readonly Action _action; + + public SyncExecutableActionOnCancellationToken(Action action) + { + _action = action; + } + + /// + public readonly object Execute(Context context, CancellationToken cancellationToken) + { + _action(cancellationToken); + return null; + } + } + + /// + internal readonly struct SyncExecutableAction : ISyncExecutable + { + private readonly Action _action; + + public SyncExecutableAction(Action action) + { + _action = action; + } + + /// + public readonly object Execute(Context context, CancellationToken cancellationToken) + { + _action(context, cancellationToken); + return null; + } + } + + internal readonly struct SyncExecutableAction : ISyncExecutable + { + private readonly Action _action; + private readonly T1 _arg1; + + public SyncExecutableAction(Action action, T1 arg1) + { + _action = action; + _arg1 = arg1; + } + + public readonly object Execute(Context context, CancellationToken cancellationToken) + { + _action(context, cancellationToken, _arg1); + return null; + } + } + + internal readonly struct SyncExecutableAction : ISyncExecutable + { + private readonly Action _action; + private readonly T1 _arg1; + private readonly T2 _arg2; + + public SyncExecutableAction(Action action, T1 arg1, T2 arg2) + { + _action = action; + _arg1 = arg1; + _arg2 = arg2; + } + + public readonly object Execute(Context context, CancellationToken cancellationToken) + { + _action(context, cancellationToken, _arg1, _arg2); + return null; + } + } + + /// + internal readonly struct SyncExecutableFuncNoParams : ISyncExecutable + { + private readonly Func _func; + + /// + /// Creates a struct for the passed func, which may be executed through a policy at a later point in time. + /// + /// The function. + public SyncExecutableFuncNoParams(Func func) + { + _func = func; + } + + /// + public readonly TResult Execute(Context context, CancellationToken cancellationToken) => _func(); + } + + /// + internal readonly struct SyncExecutableFuncOnContext : ISyncExecutable + { + private readonly Func _func; + + /// + /// Creates a struct for the passed func, which may be executed through a policy at a later point in time. + /// + /// The function. + public SyncExecutableFuncOnContext(Func func) + { + _func = func; + } + + /// + public readonly TResult Execute(Context context, CancellationToken cancellationToken) => _func(context); + } + + /// + internal readonly struct SyncExecutableFuncOnCancellationToken : ISyncExecutable + { + private readonly Func _func; + + /// + /// Creates a struct for the passed func, which may be executed through a policy at a later point in time. + /// + /// The function. + public SyncExecutableFuncOnCancellationToken(Func func) + { + _func = func; + } + + /// + public readonly TResult Execute(Context context, CancellationToken cancellationToken) => _func(cancellationToken); + } + + /// + internal readonly struct SyncExecutableFunc : ISyncExecutable + { + private readonly Func _func; + + /// + /// Creates a struct for the passed func, which may be executed through a policy at a later point in time. + /// + /// The function. + public SyncExecutableFunc(Func func) + { + _func = func; + } + + /// + public readonly TResult Execute(Context context, CancellationToken cancellationToken) => _func(context, cancellationToken); + } + + /// + internal readonly struct SyncExecutableFunc : ISyncExecutable + { + private readonly Func _func; + private readonly T1 _arg1; + + public SyncExecutableFunc(Func func, T1 arg1) + { + _func = func; + _arg1 = arg1; + } + + /// + public readonly TResult Execute(Context context, CancellationToken cancellationToken) => _func(context, cancellationToken, _arg1); + } + + /// + internal readonly struct SyncExecutableFunc : ISyncExecutable + { + private readonly Func _func; + private readonly T1 _arg1; + private readonly T2 _arg2; + + public SyncExecutableFunc(Func func, T1 arg1, T2 arg2) + { + _func = func; + _arg1 = arg1; + _arg2 = arg2; + } + + /// + public readonly TResult Execute(Context context, CancellationToken cancellationToken) => _func(context, cancellationToken, _arg1, _arg2); + } +} diff --git a/src/Polly/Timeout/AsyncTimeoutEngine.cs b/src/Polly/Timeout/AsyncTimeoutEngine.cs index 88e8d370782..829a3af8c28 100644 --- a/src/Polly/Timeout/AsyncTimeoutEngine.cs +++ b/src/Polly/Timeout/AsyncTimeoutEngine.cs @@ -7,14 +7,15 @@ namespace Polly.Timeout { internal static class AsyncTimeoutEngine { - internal static async Task ImplementationAsync( - Func> action, + internal static async Task ImplementationAsync( + TExecutableAsync action, Context context, CancellationToken cancellationToken, Func timeoutProvider, TimeoutStrategy timeoutStrategy, Func onTimeoutAsync, bool continueOnCapturedContext) + where TExecutableAsync : IAsyncExecutable { cancellationToken.ThrowIfCancellationRequested(); TimeSpan timeout = timeoutProvider(context); @@ -31,7 +32,7 @@ internal static async Task ImplementationAsync( if (timeoutStrategy == TimeoutStrategy.Optimistic) { SystemClock.CancelTokenAfter(timeoutCancellationTokenSource, timeout); - return await action(context, combinedToken).ConfigureAwait(continueOnCapturedContext); + return await action.ExecuteAsync(context, cancellationToken, continueOnCapturedContext).ConfigureAwait(continueOnCapturedContext); } // else: timeoutStrategy == TimeoutStrategy.Pessimistic @@ -40,7 +41,7 @@ internal static async Task ImplementationAsync( SystemClock.CancelTokenAfter(timeoutCancellationTokenSource, timeout); - actionTask = action(context, combinedToken); + actionTask = action.ExecuteAsync(context, cancellationToken, continueOnCapturedContext); return await (await Task.WhenAny(actionTask, timeoutTask).ConfigureAwait(continueOnCapturedContext)).ConfigureAwait(continueOnCapturedContext); diff --git a/src/Polly/Timeout/AsyncTimeoutPolicy.cs b/src/Polly/Timeout/AsyncTimeoutPolicy.cs index 3b1aa4a4817..b78cb6b218d 100644 --- a/src/Polly/Timeout/AsyncTimeoutPolicy.cs +++ b/src/Polly/Timeout/AsyncTimeoutPolicy.cs @@ -27,13 +27,13 @@ Func onTimeoutAsync /// [DebuggerStepThrough] - protected override Task ImplementationAsync( - Func> action, + protected override Task AsyncGenericImplementation( + TExecutableAsync action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) { - return AsyncTimeoutEngine.ImplementationAsync( + return AsyncTimeoutEngine.ImplementationAsync( action, context, cancellationToken, @@ -50,9 +50,9 @@ protected override Task ImplementationAsync( /// The return type of delegates which may be executed through the policy. public class AsyncTimeoutPolicy : AsyncPolicy, IAsyncTimeoutPolicy { - private Func _timeoutProvider; - private TimeoutStrategy _timeoutStrategy; - private Func _onTimeoutAsync; + private readonly Func _timeoutProvider; + private readonly TimeoutStrategy _timeoutStrategy; + private readonly Func _onTimeoutAsync; internal AsyncTimeoutPolicy( Func timeoutProvider, @@ -66,12 +66,12 @@ internal AsyncTimeoutPolicy( /// [DebuggerStepThrough] - protected override Task ImplementationAsync( - Func> action, + protected override Task AsyncGenericImplementation( + TExecutableAsync action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) - => AsyncTimeoutEngine.ImplementationAsync( + => AsyncTimeoutEngine.ImplementationAsync( action, context, cancellationToken, diff --git a/src/Polly/Timeout/AsyncTimeoutTResultSyntax.cs b/src/Polly/Timeout/AsyncTimeoutTResultSyntax.cs index 879e08ca3e5..ae06c66a405 100644 --- a/src/Polly/Timeout/AsyncTimeoutTResultSyntax.cs +++ b/src/Polly/Timeout/AsyncTimeoutTResultSyntax.cs @@ -281,8 +281,7 @@ public static IAsyncTimeoutPolicy TimeoutAsync(Func /// The policy instance. public static IAsyncTimeoutPolicy TimeoutAsync(Func timeoutProvider) { - Func doNothingAsync = (_, __, ___, ____) => Task.FromResult(default(TResult)); - return TimeoutAsync(timeoutProvider, DefaultTimeoutStrategy, doNothingAsync); + return TimeoutAsync(timeoutProvider, DefaultTimeoutStrategy, (Func) null); } /// diff --git a/src/Polly/Timeout/TimeoutEngine.cs b/src/Polly/Timeout/TimeoutEngine.cs index 6d6f73b1317..110b7b2a9e3 100644 --- a/src/Polly/Timeout/TimeoutEngine.cs +++ b/src/Polly/Timeout/TimeoutEngine.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Runtime.ExceptionServices; using System.Threading; using System.Threading.Tasks; @@ -8,13 +9,14 @@ namespace Polly.Timeout { internal static class TimeoutEngine { - internal static TResult Implementation( - Func action, + internal static TResult Implementation( + TExecutable action, Context context, CancellationToken cancellationToken, Func timeoutProvider, TimeoutStrategy timeoutStrategy, Action onTimeout) + where TExecutable : ISyncExecutable { cancellationToken.ThrowIfCancellationRequested(); TimeSpan timeout = timeoutProvider(context); @@ -31,7 +33,7 @@ internal static TResult Implementation( if (timeoutStrategy == TimeoutStrategy.Optimistic) { SystemClock.CancelTokenAfter(timeoutCancellationTokenSource, timeout); - return action(context, combinedToken); + return action.Execute(context, combinedToken); } // else: timeoutStrategy == TimeoutStrategy.Pessimistic @@ -39,7 +41,7 @@ internal static TResult Implementation( SystemClock.CancelTokenAfter(timeoutCancellationTokenSource, timeout); actionTask = Task.Run(() => - action(context, combinedToken) // cancellation token here allows the user delegate to react to cancellation: possibly clear up; then throw an OperationCanceledException. + action.Execute(context, combinedToken) // cancellation token here allows the user delegate to react to cancellation: possibly clear up; then throw an OperationCanceledException. , combinedToken); // cancellation token here only allows Task.Run() to not begin the passed delegate at all, if cancellation occurs prior to invoking the delegate. try { @@ -47,7 +49,7 @@ internal static TResult Implementation( } catch (AggregateException ex) when (ex.InnerExceptions.Count == 1) // Issue #270. Unwrap extra AggregateException caused by the way pessimistic timeout policy for synchronous executions is necessarily constructed. { - ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); + ExceptionDispatchInfo.Capture(ex.InnerExceptions.Single()).Throw(); } return actionTask.Result; diff --git a/src/Polly/Timeout/TimeoutPolicy.cs b/src/Polly/Timeout/TimeoutPolicy.cs index ebcf1b387f2..545da4d94f0 100644 --- a/src/Polly/Timeout/TimeoutPolicy.cs +++ b/src/Polly/Timeout/TimeoutPolicy.cs @@ -10,9 +10,9 @@ namespace Polly.Timeout /// public class TimeoutPolicy : Policy, ISyncTimeoutPolicy { - private Func _timeoutProvider; - private TimeoutStrategy _timeoutStrategy; - private Action _onTimeout; + private readonly Func _timeoutProvider; + private readonly TimeoutStrategy _timeoutStrategy; + private readonly Action _onTimeout; internal TimeoutPolicy( Func timeoutProvider, @@ -26,8 +26,9 @@ internal TimeoutPolicy( /// [DebuggerStepThrough] - protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken) - => TimeoutEngine.Implementation( + protected override TResult SyncGenericImplementation(in TExecutable action, Context context, + CancellationToken cancellationToken) + => TimeoutEngine.Implementation( action, context, cancellationToken, @@ -42,9 +43,9 @@ protected override TResult Implementation(FuncThe return type of delegates which may be executed through the policy. public class TimeoutPolicy : Policy, ISyncTimeoutPolicy { - private Func _timeoutProvider; - private TimeoutStrategy _timeoutStrategy; - private Action _onTimeout; + private readonly Func _timeoutProvider; + private readonly TimeoutStrategy _timeoutStrategy; + private readonly Action _onTimeout; internal TimeoutPolicy( Func timeoutProvider, @@ -57,8 +58,8 @@ internal TimeoutPolicy( } /// - protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken) - => TimeoutEngine.Implementation( + protected override TResult SyncGenericImplementation(in TExecutable action, Context context, CancellationToken cancellationToken) + => TimeoutEngine.Implementation( action, context, cancellationToken, diff --git a/src/Polly/Utilities/EmptyStruct.cs b/src/Polly/Utilities/EmptyStruct.cs deleted file mode 100644 index edc77510f76..00000000000 --- a/src/Polly/Utilities/EmptyStruct.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Polly.Utilities -{ - /// - /// A null struct for policies and actions which do not return a TResult. - /// - internal struct EmptyStruct - { - internal static readonly EmptyStruct Instance = new EmptyStruct(); - } -} diff --git a/src/Polly/Utilities/TimedLock.cs b/src/Polly/Utilities/TimedLock.cs index 6c76efe7c18..186f63ea14c 100644 --- a/src/Polly/Utilities/TimedLock.cs +++ b/src/Polly/Utilities/TimedLock.cs @@ -51,7 +51,7 @@ private TimedLock(object o) leakDetector = new Sentinel(); #endif } - private object target; + private readonly object target; public void Dispose() { @@ -81,7 +81,7 @@ private class Sentinel #endif } } - private Sentinel leakDetector; + private readonly Sentinel leakDetector; #endif } diff --git a/src/Polly/Wrap/AsyncPolicyWrap.cs b/src/Polly/Wrap/AsyncPolicyWrap.cs index 343b11bcf60..b29c0ac75ab 100644 --- a/src/Polly/Wrap/AsyncPolicyWrap.cs +++ b/src/Polly/Wrap/AsyncPolicyWrap.cs @@ -10,8 +10,8 @@ namespace Polly.Wrap /// public partial class AsyncPolicyWrap : AsyncPolicy, IAsyncPolicyWrap { - private IAsyncPolicy _outer; - private IAsyncPolicy _inner; + private readonly IAsyncPolicy _outer; + private readonly IAsyncPolicy _inner; /// /// Returns the outer in this @@ -24,8 +24,8 @@ public partial class AsyncPolicyWrap : AsyncPolicy, IAsyncPolicyWrap public IsPolicy Inner => _inner; - internal AsyncPolicyWrap(AsyncPolicy outer, IAsyncPolicy inner) - : base(outer.ExceptionPredicates) + internal AsyncPolicyWrap(IAsyncPolicy outer, IAsyncPolicy inner) + : base(((IExceptionPredicates)outer).PredicatesInternal) { _outer = outer; _inner = inner; @@ -33,10 +33,7 @@ internal AsyncPolicyWrap(AsyncPolicy outer, IAsyncPolicy inner) /// [DebuggerStepThrough] - protected override Task ImplementationAsync( - Func action, - Context context, - CancellationToken cancellationToken, + protected override Task AsyncNonGenericImplementation(in TExecutableAsync action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext) => AsyncPolicyWrapEngine.ImplementationAsync( action, @@ -49,16 +46,18 @@ protected override Task ImplementationAsync( /// [DebuggerStepThrough] - protected override Task ImplementationAsync(Func> action, Context context, CancellationToken cancellationToken, - bool continueOnCapturedContext) - => AsyncPolicyWrapEngine.ImplementationAsync( + protected override Task AsyncGenericImplementation(TExecutableAsync action, Context context, + CancellationToken cancellationToken, bool continueOnCapturedContext) + { + return AsyncPolicyWrapEngine.ImplementationAsync( action, context, cancellationToken, - continueOnCapturedContext, + continueOnCapturedContext, _outer, _inner ); + } } /// @@ -67,11 +66,11 @@ protected override Task ImplementationAsync(FuncThe return type of delegates which may be executed through the policy. public partial class AsyncPolicyWrap : AsyncPolicy, IAsyncPolicyWrap { - private IAsyncPolicy _outerNonGeneric; - private IAsyncPolicy _innerNonGeneric; + private readonly IAsyncPolicy _outerNonGeneric; + private readonly IAsyncPolicy _innerNonGeneric; - private IAsyncPolicy _outerGeneric; - private IAsyncPolicy _innerGeneric; + private readonly IAsyncPolicy _outerGeneric; + private readonly IAsyncPolicy _innerGeneric; /// /// Returns the outer in this @@ -83,36 +82,36 @@ public partial class AsyncPolicyWrap : AsyncPolicy, IAsyncPoli /// public IsPolicy Inner => (IsPolicy)_innerGeneric ?? _innerNonGeneric; - internal AsyncPolicyWrap(AsyncPolicy outer, IAsyncPolicy inner) - : base(outer.ExceptionPredicates, ResultPredicates.None) + internal AsyncPolicyWrap(IAsyncPolicy outer, IAsyncPolicy inner) + : base(((IExceptionPredicates)outer).PredicatesInternal, ResultPredicates.None) { _outerNonGeneric = outer; _innerGeneric = inner; } - internal AsyncPolicyWrap(AsyncPolicy outer, IAsyncPolicy inner) - : base(outer.ExceptionPredicates, outer.ResultPredicates) + internal AsyncPolicyWrap(IAsyncPolicy outer, IAsyncPolicy inner) + : base(((IExceptionPredicates)outer).PredicatesInternal, ((IResultPredicates)outer).PredicatesInternal) { _outerGeneric = outer; _innerNonGeneric = inner; } - internal AsyncPolicyWrap(AsyncPolicy outer, IAsyncPolicy inner) - : base(outer.ExceptionPredicates, outer.ResultPredicates) + internal AsyncPolicyWrap(IAsyncPolicy outer, IAsyncPolicy inner) + : base(((IExceptionPredicates)outer).PredicatesInternal, ((IResultPredicates)outer).PredicatesInternal) { _outerGeneric = outer; _innerGeneric = inner; } /// - protected override Task ImplementationAsync(Func> action, Context context, CancellationToken cancellationToken, - bool continueOnCapturedContext) + protected override Task AsyncGenericImplementation(TExecutableAsync action, Context context, + CancellationToken cancellationToken, bool continueOnCapturedContext) { if (_outerNonGeneric != null) { if (_innerNonGeneric != null) { - return AsyncPolicyWrapEngine.ImplementationAsync( + return AsyncPolicyWrapEngine.ImplementationAsync( action, context, cancellationToken, @@ -123,7 +122,7 @@ protected override Task ImplementationAsync(Func( + return AsyncPolicyWrapEngine.ImplementationAsync( action, context, cancellationToken, @@ -142,7 +141,7 @@ protected override Task ImplementationAsync(Func( + return AsyncPolicyWrapEngine.ImplementationAsync( action, context, cancellationToken, @@ -154,7 +153,7 @@ protected override Task ImplementationAsync(Func( + return AsyncPolicyWrapEngine.ImplementationAsync( action, context, cancellationToken, diff --git a/src/Polly/Wrap/AsyncPolicyWrapEngine.cs b/src/Polly/Wrap/AsyncPolicyWrapEngine.cs index 18b33157062..bb62392c356 100644 --- a/src/Polly/Wrap/AsyncPolicyWrapEngine.cs +++ b/src/Polly/Wrap/AsyncPolicyWrapEngine.cs @@ -1,105 +1,128 @@ -using System; -using System.Threading; +using System.Threading; using System.Threading.Tasks; namespace Polly.Wrap { internal static class AsyncPolicyWrapEngine { - internal static async Task ImplementationAsync( - Func> func, + internal static Task ImplementationAsync( + TExecutableAsync func, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, IAsyncPolicy outerPolicy, IAsyncPolicy innerPolicy) - => await outerPolicy.ExecuteAsync( - async (ctx, ct) => await innerPolicy.ExecuteAsync( - func, - ctx, - ct, - continueOnCapturedContext - ).ConfigureAwait(continueOnCapturedContext), - context, - cancellationToken, - continueOnCapturedContext - ).ConfigureAwait(continueOnCapturedContext); + where TExecutableAsync : IAsyncExecutable + { + return outerPolicy.ExecuteAsync, TExecutableAsync>( + (ctx, ct, captureContext, inner, userFunc) => ((IAsyncPolicyInternal)inner).ExecuteAsync( + userFunc, + ctx, + ct, + captureContext + ), + context, + cancellationToken, + continueOnCapturedContext, + innerPolicy, + func + ); + } - internal static async Task ImplementationAsync( - Func> func, + internal static Task ImplementationAsync( + TExecutableAsync func, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, IAsyncPolicy outerPolicy, IAsyncPolicy innerPolicy) - => await outerPolicy.ExecuteAsync( - async (ctx, ct) => await innerPolicy.ExecuteAsync( - func, + where TExecutableAsync : IAsyncExecutable + { + return outerPolicy.ExecuteAsync( + (ctx, ct, captureContext, inner, userFunc) => ((IAsyncPolicyInternal)inner).ExecuteAsync( + userFunc, ctx, ct, - continueOnCapturedContext - ).ConfigureAwait(continueOnCapturedContext), + captureContext + ), context, cancellationToken, - continueOnCapturedContext - ).ConfigureAwait(continueOnCapturedContext); + continueOnCapturedContext, + innerPolicy, + func + ); + } - internal static async Task ImplementationAsync( - Func> func, + internal static Task ImplementationAsync( + TExecutableAsync func, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, IAsyncPolicy outerPolicy, IAsyncPolicy innerPolicy) - => await outerPolicy.ExecuteAsync( - async (ctx, ct) => await innerPolicy.ExecuteAsync( - func, + where TExecutableAsync : IAsyncExecutable + { + return outerPolicy.ExecuteAsync, TExecutableAsync, TResult>( + (ctx, ct, captureContext, inner, userFunc) => ((IAsyncPolicyInternal)inner).ExecuteAsync( + userFunc, ctx, ct, - continueOnCapturedContext - ).ConfigureAwait(continueOnCapturedContext), + captureContext + ), context, cancellationToken, - continueOnCapturedContext - ).ConfigureAwait(continueOnCapturedContext); + continueOnCapturedContext, + innerPolicy, + func + ); + } - internal static async Task ImplementationAsync( - Func> func, - Context context, - CancellationToken cancellationToken, - bool continueOnCapturedContext, - IAsyncPolicy outerPolicy, - IAsyncPolicy innerPolicy) - => await outerPolicy.ExecuteAsync( - async (ctx, ct) => await innerPolicy.ExecuteAsync( - func, + internal static Task ImplementationAsync( + TExecutableAsync func, + Context context, + CancellationToken cancellationToken, + bool continueOnCapturedContext, + IAsyncPolicy outerPolicy, + IAsyncPolicy innerPolicy) + where TExecutableAsync : IAsyncExecutable + { + return outerPolicy.ExecuteAsync( + (ctx, ct, captureContext, inner, userFunc) => ((IAsyncPolicyInternal)inner).ExecuteAsync( + userFunc, ctx, ct, - continueOnCapturedContext - ).ConfigureAwait(continueOnCapturedContext), + captureContext + ), context, cancellationToken, - continueOnCapturedContext - ).ConfigureAwait(continueOnCapturedContext); + continueOnCapturedContext, + innerPolicy, + func + ); + } - internal static async Task ImplementationAsync( - Func action, + internal static Task ImplementationAsync( + TExecutableAsync action, Context context, CancellationToken cancellationToken, bool continueOnCapturedContext, IAsyncPolicy outerPolicy, IAsyncPolicy innerPolicy) - => await outerPolicy.ExecuteAsync( - async (ctx, ct) => await innerPolicy.ExecuteAsync( - action, + where TExecutableAsync : IAsyncExecutable + { + return outerPolicy.ExecuteAsync( + (ctx, ct, captureContext, inner, userAction) => ((IAsyncPolicyInternal)inner).ExecuteAsync( + userAction, ctx, ct, - continueOnCapturedContext - ).ConfigureAwait(continueOnCapturedContext), + captureContext + ), context, cancellationToken, - continueOnCapturedContext - ).ConfigureAwait(continueOnCapturedContext); - + continueOnCapturedContext, + innerPolicy, + action + ); + } } } diff --git a/src/Polly/Wrap/AsyncPolicyWrapSyntax.cs b/src/Polly/Wrap/AsyncPolicyWrapSyntax.cs index ad879b3093e..7406c88d559 100644 --- a/src/Polly/Wrap/AsyncPolicyWrapSyntax.cs +++ b/src/Polly/Wrap/AsyncPolicyWrapSyntax.cs @@ -4,73 +4,6 @@ namespace Polly { - public partial class AsyncPolicy - { - /// - /// Wraps the specified inner policy. - /// - /// The inner policy. - /// PolicyWrap.PolicyWrap. - public IAsyncPolicyWrap WrapAsync(IAsyncPolicy innerPolicy) - { - if (innerPolicy == null) throw new ArgumentNullException(nameof(innerPolicy)); - - return new AsyncPolicyWrap( - this, - innerPolicy - ); - } - - /// - /// Wraps the specified inner policy. - /// - /// The inner policy. - /// The return type of delegates which may be executed through the policy. - /// PolicyWrap.PolicyWrap. - public IAsyncPolicyWrap WrapAsync(IAsyncPolicy innerPolicy) - { - if (innerPolicy == null) throw new ArgumentNullException(nameof(innerPolicy)); - - return new AsyncPolicyWrap( - this, - innerPolicy - ); - } - } - - public partial class AsyncPolicy - { - /// - /// Wraps the specified inner policy. - /// - /// The inner policy. - /// PolicyWrap.PolicyWrap. - public IAsyncPolicyWrap WrapAsync(IAsyncPolicy innerPolicy) - { - if (innerPolicy == null) throw new ArgumentNullException(nameof(innerPolicy)); - - return new AsyncPolicyWrap( - this, - innerPolicy - ); - } - - /// - /// Wraps the specified inner policy. - /// - /// The inner policy. - /// PolicyWrap.PolicyWrap. - public IAsyncPolicyWrap WrapAsync(IAsyncPolicy innerPolicy) - { - if (innerPolicy == null) throw new ArgumentNullException(nameof(innerPolicy)); - - return new AsyncPolicyWrap( - this, - innerPolicy - ); - } - } - public partial class Policy { /// @@ -87,7 +20,7 @@ public static IAsyncPolicyWrap WrapAsync(params IAsyncPolicy[] policies) case 1: throw new ArgumentException("The enumerable of policies to form the wrap must contain at least two policies.", nameof(policies)); case 2: - return new AsyncPolicyWrap((AsyncPolicy)policies[0], policies[1]); + return new AsyncPolicyWrap(policies[0], policies[1]); default: return WrapAsync(policies[0], WrapAsync(policies.Skip(1).ToArray())); @@ -109,7 +42,7 @@ public static IAsyncPolicyWrap WrapAsync(params IAsyncPolicy((AsyncPolicy)policies[0], policies[1]); + return new AsyncPolicyWrap(policies[0], policies[1]); default: return WrapAsync(policies[0], WrapAsync(policies.Skip(1).ToArray())); @@ -123,7 +56,7 @@ public static IAsyncPolicyWrap WrapAsync(params IAsyncPolicy - /// Wraps the specified outer policy round the inner policy. + /// Wraps the given outer policy round the inner policy. /// /// The outer policy. /// The inner policy. @@ -131,11 +64,16 @@ public static class IAsyncPolicyPolicyWrapExtensions public static IAsyncPolicyWrap WrapAsync(this IAsyncPolicy outerPolicy, IAsyncPolicy innerPolicy) { if (outerPolicy == null) throw new ArgumentNullException(nameof(outerPolicy)); - return ((AsyncPolicy)outerPolicy).WrapAsync(innerPolicy); + if (innerPolicy == null) throw new ArgumentNullException(nameof(innerPolicy)); + + return new AsyncPolicyWrap( + outerPolicy, + innerPolicy + ); } /// - /// Wraps the specified outer policy round the inner policy. + /// Wraps the given outer policy round the inner policy. /// /// The outer policy. /// The inner policy. @@ -143,11 +81,16 @@ public static IAsyncPolicyWrap WrapAsync(this IAsyncPolicy outerPolicy, IAsyncPo public static IAsyncPolicyWrap WrapAsync(this IAsyncPolicy outerPolicy, IAsyncPolicy innerPolicy) { if (outerPolicy == null) throw new ArgumentNullException(nameof(outerPolicy)); - return ((AsyncPolicy)outerPolicy).WrapAsync(innerPolicy); + if (innerPolicy == null) throw new ArgumentNullException(nameof(innerPolicy)); + + return new AsyncPolicyWrap( + outerPolicy, + innerPolicy + ); } /// - /// Wraps the specified outer policy round the inner policy. + /// Wraps the given outer policy round the inner policy. /// /// The outer policy. /// The inner policy. @@ -155,11 +98,16 @@ public static IAsyncPolicyWrap WrapAsync(this IAsyncPolicy out public static IAsyncPolicyWrap WrapAsync(this IAsyncPolicy outerPolicy, IAsyncPolicy innerPolicy) { if (outerPolicy == null) throw new ArgumentNullException(nameof(outerPolicy)); - return ((AsyncPolicy)outerPolicy).WrapAsync(innerPolicy); + if (innerPolicy == null) throw new ArgumentNullException(nameof(innerPolicy)); + + return new AsyncPolicyWrap( + outerPolicy, + innerPolicy + ); } /// - /// Wraps the specified outer policy round the inner policy. + /// Wraps the given outer policy round the inner policy. /// /// The outer policy. /// The inner policy. @@ -167,7 +115,12 @@ public static IAsyncPolicyWrap WrapAsync(this IAsyncPolicy WrapAsync(this IAsyncPolicy outerPolicy, IAsyncPolicy innerPolicy) { if (outerPolicy == null) throw new ArgumentNullException(nameof(outerPolicy)); - return ((AsyncPolicy)outerPolicy).WrapAsync(innerPolicy); + if (innerPolicy == null) throw new ArgumentNullException(nameof(innerPolicy)); + + return new AsyncPolicyWrap( + outerPolicy, + innerPolicy + ); } } } diff --git a/src/Polly/Wrap/PolicyWrap.cs b/src/Polly/Wrap/PolicyWrap.cs index f287c2a492c..3312da23871 100644 --- a/src/Polly/Wrap/PolicyWrap.cs +++ b/src/Polly/Wrap/PolicyWrap.cs @@ -9,8 +9,8 @@ namespace Polly.Wrap /// public partial class PolicyWrap : Policy, ISyncPolicyWrap { - private ISyncPolicy _outer; - private ISyncPolicy _inner; + private readonly ISyncPolicy _outer; + private readonly ISyncPolicy _inner; /// /// Returns the outer in this @@ -22,8 +22,8 @@ public partial class PolicyWrap : Policy, ISyncPolicyWrap /// public IsPolicy Inner => _inner; - internal PolicyWrap(Policy outer, ISyncPolicy inner) - : base(outer.ExceptionPredicates) + internal PolicyWrap(ISyncPolicy outer, ISyncPolicy inner) + : base(((IExceptionPredicates)outer).PredicatesInternal) { _outer = outer; _inner = inner; @@ -31,7 +31,7 @@ internal PolicyWrap(Policy outer, ISyncPolicy inner) /// [DebuggerStepThrough] - protected override void Implementation(Action action, Context context, CancellationToken cancellationToken) + protected override void SyncNonGenericImplementation(in TExecutable action, Context context, CancellationToken cancellationToken) => PolicyWrapEngine.Implementation( action, context, @@ -42,8 +42,9 @@ protected override void Implementation(Action action /// [DebuggerStepThrough] - protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken) - => PolicyWrapEngine.Implementation( + protected override TResult SyncGenericImplementation(in TExecutable action, Context context, + CancellationToken cancellationToken) + => PolicyWrapEngine.Implementation( action, context, cancellationToken, @@ -58,11 +59,11 @@ protected override TResult Implementation(FuncThe return type of delegates which may be executed through the policy. public partial class PolicyWrap : Policy, ISyncPolicyWrap { - private ISyncPolicy _outerNonGeneric; - private ISyncPolicy _innerNonGeneric; + private readonly ISyncPolicy _outerNonGeneric; + private readonly ISyncPolicy _innerNonGeneric; - private ISyncPolicy _outerGeneric; - private ISyncPolicy _innerGeneric; + private readonly ISyncPolicy _outerGeneric; + private readonly ISyncPolicy _innerGeneric; /// /// Returns the outer in this @@ -74,35 +75,35 @@ public partial class PolicyWrap : Policy, ISyncPolicyWrap public IsPolicy Inner => (IsPolicy)_innerGeneric ?? _innerNonGeneric; - internal PolicyWrap(Policy outer, ISyncPolicy inner) - : base(outer.ExceptionPredicates, ResultPredicates.None) + internal PolicyWrap(ISyncPolicy outer, ISyncPolicy inner) + : base(((IExceptionPredicates)outer).PredicatesInternal, ResultPredicates.None) { _outerNonGeneric = outer; _innerGeneric = inner; } - internal PolicyWrap(Policy outer, ISyncPolicy inner) - : base(outer.ExceptionPredicates, outer.ResultPredicates) + internal PolicyWrap(ISyncPolicy outer, ISyncPolicy inner) + : base(((IExceptionPredicates)outer).PredicatesInternal, ((IResultPredicates)outer).PredicatesInternal) { _outerGeneric = outer; _innerNonGeneric = inner; } - internal PolicyWrap(Policy outer, ISyncPolicy inner) - : base(outer.ExceptionPredicates, outer.ResultPredicates) + internal PolicyWrap(ISyncPolicy outer, ISyncPolicy inner) + : base(((IExceptionPredicates)outer).PredicatesInternal, ((IResultPredicates)outer).PredicatesInternal) { _outerGeneric = outer; _innerGeneric = inner; } /// - protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken) + protected override TResult SyncGenericImplementation(in TExecutable action, Context context, CancellationToken cancellationToken) { if (_outerNonGeneric != null) { if (_innerNonGeneric != null) { - return PolicyWrapEngine.Implementation( + return PolicyWrapEngine.Implementation( action, context, cancellationToken, @@ -112,7 +113,7 @@ protected override TResult Implementation(Func( + return PolicyWrapEngine.Implementation( action, context, cancellationToken, @@ -130,7 +131,7 @@ protected override TResult Implementation(Func( + return PolicyWrapEngine.Implementation( action, context, cancellationToken, @@ -141,7 +142,7 @@ protected override TResult Implementation(Func( + return PolicyWrapEngine.Implementation( action, context, cancellationToken, diff --git a/src/Polly/Wrap/PolicyWrapEngine.cs b/src/Polly/Wrap/PolicyWrapEngine.cs index 88cca6ab465..bc1293812b3 100644 --- a/src/Polly/Wrap/PolicyWrapEngine.cs +++ b/src/Polly/Wrap/PolicyWrapEngine.cs @@ -1,48 +1,87 @@ -using System; -using System.Threading; +using System.Threading; namespace Polly.Wrap { internal static class PolicyWrapEngine { - internal static TResult Implementation( - Func func, + internal static TResult Implementation( + TExecutable func, Context context, CancellationToken cancellationToken, ISyncPolicy outerPolicy, ISyncPolicy innerPolicy) - => outerPolicy.Execute((ctx, ct) => innerPolicy.Execute(func, ctx, ct), context, cancellationToken); + where TExecutable : ISyncExecutable + { + return outerPolicy.Execute, TExecutable>( + (ctx, ct, inner, userFunc) => ((ISyncPolicyInternal)inner).Execute(userFunc, ctx, ct), + context, + cancellationToken, + innerPolicy, + func); + } - internal static TResult Implementation( - Func func, - Context context, - CancellationToken cancellationToken, - ISyncPolicy outerPolicy, - ISyncPolicy innerPolicy) - => outerPolicy.Execute((ctx, ct) => innerPolicy.Execute(func, ctx, ct), context, cancellationToken); + internal static TResult Implementation( + TExecutable func, + Context context, + CancellationToken cancellationToken, + ISyncPolicy outerPolicy, + ISyncPolicy innerPolicy) + where TExecutable : ISyncExecutable + { + return outerPolicy.Execute( + (ctx, ct, inner, userFunc) => ((ISyncPolicyInternal)inner).Execute(userFunc, ctx, ct), + context, + cancellationToken, + innerPolicy, + func); + } - internal static TResult Implementation( - Func func, - Context context, - CancellationToken cancellationToken, - ISyncPolicy outerPolicy, - ISyncPolicy innerPolicy) - => outerPolicy.Execute((ctx, ct) => innerPolicy.Execute(func, ctx, ct), context, cancellationToken); + internal static TResult Implementation( + TExecutable func, + Context context, + CancellationToken cancellationToken, + ISyncPolicy outerPolicy, + ISyncPolicy innerPolicy) + where TExecutable : ISyncExecutable + { + return outerPolicy.Execute, TExecutable, TResult>( + (ctx, ct, inner, userFunc) => ((ISyncPolicyInternal)inner).Execute(userFunc, ctx, ct), + context, + cancellationToken, + innerPolicy, + func); + } - internal static TResult Implementation( - Func func, - Context context, - CancellationToken cancellationToken, - ISyncPolicy outerPolicy, - ISyncPolicy innerPolicy) - => outerPolicy.Execute((ctx, ct) => innerPolicy.Execute(func, ctx, ct), context, cancellationToken); + internal static TResult Implementation( + TExecutable func, + Context context, + CancellationToken cancellationToken, + ISyncPolicy outerPolicy, + ISyncPolicy innerPolicy) + where TExecutable : ISyncExecutable + { + return outerPolicy.Execute( + (ctx, ct, inner, userFunc) => ((ISyncPolicyInternal) inner).Execute(userFunc, ctx, ct), + context, + cancellationToken, + innerPolicy, + func); + } - internal static void Implementation( - Action action, - Context context, - CancellationToken cancellationToken, - ISyncPolicy outerPolicy, - ISyncPolicy innerPolicy) - => outerPolicy.Execute((ctx, ct) => innerPolicy.Execute(action, ctx, ct), context, cancellationToken); + internal static void Implementation( + TExecutable action, + Context context, + CancellationToken cancellationToken, + ISyncPolicy outerPolicy, + ISyncPolicy innerPolicy) + where TExecutable : ISyncExecutable + { + outerPolicy.Execute( + (ctx, ct, inner, userAction) => ((ISyncPolicyInternal) inner).Execute(userAction, ctx, ct), + context, + cancellationToken, + innerPolicy, + action); + } } } diff --git a/src/Polly/Wrap/PolicyWrapSyntax.cs b/src/Polly/Wrap/PolicyWrapSyntax.cs index 5385f680e97..ffaf9a3d9e0 100644 --- a/src/Polly/Wrap/PolicyWrapSyntax.cs +++ b/src/Polly/Wrap/PolicyWrapSyntax.cs @@ -4,73 +4,6 @@ namespace Polly { - public partial class Policy - { - /// - /// Wraps the specified inner policy. - /// - /// The inner policy. - /// PolicyWrap.PolicyWrap. - public ISyncPolicyWrap Wrap(ISyncPolicy innerPolicy) - { - if (innerPolicy == null) throw new ArgumentNullException(nameof(innerPolicy)); - - return new PolicyWrap( - this, - innerPolicy - ); - } - - /// - /// Wraps the specified inner policy. - /// - /// The inner policy. - /// The return type of delegates which may be executed through the policy. - /// PolicyWrap.PolicyWrap. - public ISyncPolicyWrap Wrap(ISyncPolicy innerPolicy) - { - if (innerPolicy == null) throw new ArgumentNullException(nameof(innerPolicy)); - - return new PolicyWrap( - this, - innerPolicy - ); - } - } - - public partial class Policy - { - /// - /// Wraps the specified inner policy. - /// - /// The inner policy. - /// PolicyWrap.PolicyWrap. - public ISyncPolicyWrap Wrap(ISyncPolicy innerPolicy) - { - if (innerPolicy == null) throw new ArgumentNullException(nameof(innerPolicy)); - - return new PolicyWrap( - this, - innerPolicy - ); - } - - /// - /// Wraps the specified inner policy. - /// - /// The inner policy. - /// PolicyWrap.PolicyWrap. - public ISyncPolicyWrap Wrap(ISyncPolicy innerPolicy) - { - if (innerPolicy == null) throw new ArgumentNullException(nameof(innerPolicy)); - - return new PolicyWrap( - this, - innerPolicy - ); - } - } - public partial class Policy { /// @@ -87,7 +20,7 @@ public static ISyncPolicyWrap Wrap(params ISyncPolicy[] policies) case 1: throw new ArgumentException("The enumerable of policies to form the wrap must contain at least two policies.", nameof(policies)); case 2: - return new PolicyWrap((Policy)policies[0], policies[1]); + return new PolicyWrap(policies[0], policies[1]); default: return Wrap(policies[0], Wrap(policies.Skip(1).ToArray())); @@ -109,7 +42,7 @@ public static ISyncPolicyWrap Wrap(params ISyncPolicy case 1: throw new ArgumentException("The enumerable of policies to form the wrap must contain at least two policies.", nameof(policies)); case 2: - return new PolicyWrap((Policy)policies[0], policies[1]); + return new PolicyWrap(policies[0], policies[1]); default: return Wrap(policies[0], Wrap(policies.Skip(1).ToArray())); @@ -123,7 +56,7 @@ public static ISyncPolicyWrap Wrap(params ISyncPolicy public static class ISyncPolicyPolicyWrapExtensions { /// - /// Wraps the specified outer policy round the inner policy. + /// Wraps the given outer policy round the inner policy. /// /// The outer policy. /// The inner policy. @@ -131,11 +64,16 @@ public static class ISyncPolicyPolicyWrapExtensions public static ISyncPolicyWrap Wrap(this ISyncPolicy outerPolicy, ISyncPolicy innerPolicy) { if (outerPolicy == null) throw new ArgumentNullException(nameof(outerPolicy)); - return ((Policy) outerPolicy).Wrap(innerPolicy); + if (innerPolicy == null) throw new ArgumentNullException(nameof(innerPolicy)); + + return new PolicyWrap( + outerPolicy, + innerPolicy + ); } /// - /// Wraps the specified outer policy round the inner policy. + /// Wraps the given outer policy round the inner policy. /// /// The outer policy. /// The inner policy. @@ -143,11 +81,16 @@ public static ISyncPolicyWrap Wrap(this ISyncPolicy outerPolicy, ISyncPolicy inn public static ISyncPolicyWrap Wrap(this ISyncPolicy outerPolicy, ISyncPolicy innerPolicy) { if (outerPolicy == null) throw new ArgumentNullException(nameof(outerPolicy)); - return ((Policy)outerPolicy).Wrap(innerPolicy); + if (innerPolicy == null) throw new ArgumentNullException(nameof(innerPolicy)); + + return new PolicyWrap( + outerPolicy, + innerPolicy + ); } /// - /// Wraps the specified outer policy round the inner policy. + /// Wraps the given outer policy round the inner policy. /// /// The outer policy. /// The inner policy. @@ -155,11 +98,16 @@ public static ISyncPolicyWrap Wrap(this ISyncPolicy outerPolic public static ISyncPolicyWrap Wrap(this ISyncPolicy outerPolicy, ISyncPolicy innerPolicy) { if (outerPolicy == null) throw new ArgumentNullException(nameof(outerPolicy)); - return ((Policy)outerPolicy).Wrap(innerPolicy); + if (innerPolicy == null) throw new ArgumentNullException(nameof(innerPolicy)); + + return new PolicyWrap( + outerPolicy, + innerPolicy + ); } /// - /// Wraps the specified outer policy round the inner policy. + /// Wraps the given outer policy round the inner policy. /// /// The outer policy. /// The inner policy. @@ -167,7 +115,12 @@ public static ISyncPolicyWrap Wrap(this ISyncPolicy o public static ISyncPolicyWrap Wrap(this ISyncPolicy outerPolicy, ISyncPolicy innerPolicy) { if (outerPolicy == null) throw new ArgumentNullException(nameof(outerPolicy)); - return ((Policy)outerPolicy).Wrap(innerPolicy); + if (innerPolicy == null) throw new ArgumentNullException(nameof(innerPolicy)); + + return new PolicyWrap( + outerPolicy, + innerPolicy + ); } } }