From 5b55740c30f610c9210dd5eee004a1f6033873dd Mon Sep 17 00:00:00 2001 From: martintmk Date: Tue, 2 May 2023 08:49:18 +0200 Subject: [PATCH] Add more execute methods for ResilienceStrategy --- .../ResilienceStrategyTests.Async.Task.cs | 13 ++ .../ResilienceStrategyTests.Async.TaskT.cs | 18 +++ ...ResilienceStrategyTests.Async.ValueTask.cs | 19 +++ ...esilienceStrategyTests.Async.ValueTaskT.cs | 18 +++ .../ResilienceStrategyTests.Sync.cs | 25 ++++ .../ResilienceStrategyTests.SyncT.cs | 28 ++++- .../Retry/RetryResilienceStrategyTests.cs | 16 +-- .../ResilienceStrategy.Async.Task.cs | 59 +++++++++ .../ResilienceStrategy.Async.TaskT.cs | 61 ++++++++++ .../ResilienceStrategy.Async.ValueTask.cs | 59 +++++++++ .../ResilienceStrategy.Async.ValueTaskT.cs | 50 ++++++++ src/Polly.Core/ResilienceStrategy.Sync.cs | 115 ++++++++++++++++++ src/Polly.Core/ResilienceStrategy.SyncT.cs | 105 ++++++++++++++++ 13 files changed, 576 insertions(+), 10 deletions(-) diff --git a/src/Polly.Core.Tests/ResilienceStrategyTests.Async.Task.cs b/src/Polly.Core.Tests/ResilienceStrategyTests.Async.Task.cs index a95031d1614..7458ba896f4 100644 --- a/src/Polly.Core.Tests/ResilienceStrategyTests.Async.Task.cs +++ b/src/Polly.Core.Tests/ResilienceStrategyTests.Async.Task.cs @@ -23,6 +23,12 @@ private static IEnumerable ExecuteAsTaskAsync_EnsureCorrectBe AssertContext = AssertResilienceContextAndToken, }; + yield return new ExecuteParameters(r => r.ExecuteAsync(async (state, t) => { state.Should().Be("state"); t.Should().Be(CancellationToken); }, "state", CancellationToken)) + { + Caption = "ExecuteAsTaskAsync_StateAndCancellation", + AssertContext = AssertResilienceContextAndToken, + }; + yield return new ExecuteParameters(r => r.ExecuteAsync(async (_, s) => { s.Should().Be("dummy-state"); }, ResilienceContext.Get(), "dummy-state")) { Caption = "ExecuteAsTaskAsync_ResilienceContextAndState", @@ -30,6 +36,13 @@ private static IEnumerable ExecuteAsTaskAsync_EnsureCorrectBe AssertContextAfter = AssertContextInitialized, }; + yield return new ExecuteParameters(r => r.ExecuteAsync(async context => { }, ResilienceContext.Get())) + { + Caption = "ExecuteAsTaskAsync_ResilienceContextAndState", + AssertContext = AssertResilienceContext, + AssertContextAfter = AssertContextInitialized, + }; + static void AssertResilienceContext(ResilienceContext context) { context.IsSynchronous.Should().BeFalse(); diff --git a/src/Polly.Core.Tests/ResilienceStrategyTests.Async.TaskT.cs b/src/Polly.Core.Tests/ResilienceStrategyTests.Async.TaskT.cs index 935c36ba0ec..cad51a98b00 100644 --- a/src/Polly.Core.Tests/ResilienceStrategyTests.Async.TaskT.cs +++ b/src/Polly.Core.Tests/ResilienceStrategyTests.Async.TaskT.cs @@ -25,6 +25,17 @@ private static IEnumerable ExecuteAsTaskAsyncT_EnsureCorrectB AssertContext = AssertResilienceContextAndToken, }; + yield return new ExecuteParameters(r => r.ExecuteAsync(async (state, t) => + { + state.Should().Be("state"); + t.Should().Be(CancellationToken); + return result; + }, "state", CancellationToken), result) + { + Caption = "ExecuteAsTaskAsyncT_CancellationAndState", + AssertContext = AssertResilienceContextAndToken, + }; + yield return new ExecuteParameters(r => r.ExecuteAsync(async (_, s) => { s.Should().Be("dummy-state"); return result; }, ResilienceContext.Get(), "dummy-state"), result) { Caption = "ExecuteAsTaskAsyncT_ResilienceContextAndState", @@ -32,6 +43,13 @@ private static IEnumerable ExecuteAsTaskAsyncT_EnsureCorrectB AssertContextAfter = AssertContextInitialized, }; + yield return new ExecuteParameters(r => r.ExecuteAsync(async context => result, ResilienceContext.Get()), result) + { + Caption = "ExecuteAsTaskAsyncT_ResilienceContext", + AssertContext = AssertResilienceContext, + AssertContextAfter = AssertContextInitialized, + }; + static void AssertResilienceContext(ResilienceContext context) { context.IsSynchronous.Should().BeFalse(); diff --git a/src/Polly.Core.Tests/ResilienceStrategyTests.Async.ValueTask.cs b/src/Polly.Core.Tests/ResilienceStrategyTests.Async.ValueTask.cs index 66584d9e142..3d80c3f535d 100644 --- a/src/Polly.Core.Tests/ResilienceStrategyTests.Async.ValueTask.cs +++ b/src/Polly.Core.Tests/ResilienceStrategyTests.Async.ValueTask.cs @@ -23,6 +23,18 @@ private static IEnumerable ExecuteAsync_EnsureCorrectBehavior AssertContext = AssertResilienceContextAndToken, }; + yield return new ExecuteParameters(r => r.ExecuteValueTaskAsync(async (state, t) => { state.Should().Be("state"); t.Should().Be(CancellationToken); }, "state", CancellationToken)) + { + Caption = "ExecuteAsync_StateAndCancellation", + AssertContext = AssertResilienceContextAndToken, + }; + + yield return new ExecuteParameters(r => r.ExecuteValueTaskAsync(async (state, t) => { state.Should().Be("state"); t.Should().Be(CancellationToken); }, "state", CancellationToken)) + { + Caption = "ExecuteAsync_StateAndCancellation", + AssertContext = AssertResilienceContextAndToken, + }; + yield return new ExecuteParameters(r => r.ExecuteValueTaskAsync(async (_, s) => { s.Should().Be("dummy-state"); }, ResilienceContext.Get(), "dummy-state")) { Caption = "ExecuteAsync_ResilienceContextAndState", @@ -30,6 +42,13 @@ private static IEnumerable ExecuteAsync_EnsureCorrectBehavior AssertContextAfter = AssertContextInitialized, }; + yield return new ExecuteParameters(r => r.ExecuteValueTaskAsync(context => default, ResilienceContext.Get())) + { + Caption = "ExecuteAsync_ResilienceContext", + AssertContext = AssertResilienceContext, + AssertContextAfter = AssertContextInitialized, + }; + static void AssertResilienceContext(ResilienceContext context) { context.IsSynchronous.Should().BeFalse(); diff --git a/src/Polly.Core.Tests/ResilienceStrategyTests.Async.ValueTaskT.cs b/src/Polly.Core.Tests/ResilienceStrategyTests.Async.ValueTaskT.cs index caa8d1e3129..6b69adb8bad 100644 --- a/src/Polly.Core.Tests/ResilienceStrategyTests.Async.ValueTaskT.cs +++ b/src/Polly.Core.Tests/ResilienceStrategyTests.Async.ValueTaskT.cs @@ -25,6 +25,17 @@ private static IEnumerable ExecuteAsyncT_EnsureCorrectBehavio AssertContext = AssertResilienceContextAndToken, }; + yield return new ExecuteParameters(r => r.ExecuteValueTaskAsync(async (state, t) => + { + state.Should().Be("state"); + t.Should().Be(CancellationToken); + return result; + }, "state", CancellationToken), result) + { + Caption = "ExecuteAsyncT_StateAndCancellation", + AssertContext = AssertResilienceContextAndToken, + }; + yield return new ExecuteParameters(r => r.ExecuteValueTaskAsync(async (_, s) => { s.Should().Be("dummy-state"); return result; }, ResilienceContext.Get(), "dummy-state"), result) { Caption = "ExecuteAsyncT_ResilienceContextAndState", @@ -32,6 +43,13 @@ private static IEnumerable ExecuteAsyncT_EnsureCorrectBehavio AssertContextAfter = AssertContextInitialized, }; + yield return new ExecuteParameters(r => r.ExecuteValueTaskAsync(async _ => result, ResilienceContext.Get()), result) + { + Caption = "ExecuteAsyncT_ResilienceContext", + AssertContext = AssertResilienceContext, + AssertContextAfter = AssertContextInitialized, + }; + static void AssertResilienceContext(ResilienceContext context) { context.IsSynchronous.Should().BeFalse(); diff --git a/src/Polly.Core.Tests/ResilienceStrategyTests.Sync.cs b/src/Polly.Core.Tests/ResilienceStrategyTests.Sync.cs index ed79a097c42..938907db25c 100644 --- a/src/Polly.Core.Tests/ResilienceStrategyTests.Sync.cs +++ b/src/Polly.Core.Tests/ResilienceStrategyTests.Sync.cs @@ -21,6 +21,31 @@ private static IEnumerable Execute_EnsureCorrectBehavior_Exec AssertContext = AssertResilienceContextAndToken, }; + yield return new ExecuteParameters(r => r.Execute((state, t) => { state.Should().Be("state"); t.Should().Be(CancellationToken); }, "state", CancellationToken)) + { + Caption = "Execute_StateAndCancellation", + AssertContext = AssertResilienceContextAndToken, + }; + + yield return new ExecuteParameters(r => r.Execute(() => { })) + { + Caption = "Execute", + AssertContext = AssertResilienceContext, + }; + + yield return new ExecuteParameters(r => r.Execute(state => { state.Should().Be("state"); }, "state")) + { + Caption = "ExecuteAndState", + AssertContext = AssertResilienceContext, + }; + + yield return new ExecuteParameters(r => r.Execute(context => { }, ResilienceContext.Get())) + { + Caption = "ResilienceContext", + AssertContext = AssertResilienceContext, + AssertContextAfter = AssertContextInitialized, + }; + yield return new ExecuteParameters(r => r.Execute((_, s) => { s.Should().Be("dummy-state"); }, ResilienceContext.Get(), "dummy-state")) { Caption = "Execute_ResilienceContextAndState", diff --git a/src/Polly.Core.Tests/ResilienceStrategyTests.SyncT.cs b/src/Polly.Core.Tests/ResilienceStrategyTests.SyncT.cs index 78099574daa..dd352a03589 100644 --- a/src/Polly.Core.Tests/ResilienceStrategyTests.SyncT.cs +++ b/src/Polly.Core.Tests/ResilienceStrategyTests.SyncT.cs @@ -23,11 +23,35 @@ private static IEnumerable ExecuteT_EnsureCorrectBehavior_Exe AssertContext = AssertResilienceContextAndToken, }; + yield return new ExecuteParameters(r => r.Execute(() => result), result) + { + Caption = "ExecuteT", + AssertContext = AssertResilienceContext, + }; + + yield return new ExecuteParameters(r => r.Execute((state) => { state.Should().Be("state"); return result; }, "state"), result) + { + Caption = "ExecuteT_State", + AssertContext = AssertResilienceContext, + }; + + yield return new ExecuteParameters(r => r.Execute(_ => result, ResilienceContext.Get()), result) + { + Caption = "ExecuteT_ResilienceContext", + AssertContext = AssertResilienceContext, + AssertContextAfter = AssertContextInitialized + }; + yield return new ExecuteParameters(r => r.Execute((_, s) => { s.Should().Be("dummy-state"); return result; }, ResilienceContext.Get(), "dummy-state"), result) { - Caption = "ExecuteT_ResilienceContextAndState", + Caption = "ExecuteT_ResilienceContext", AssertContext = AssertResilienceContext, - AssertContextAfter = AssertContextInitialized, + }; + + yield return new ExecuteParameters(r => r.Execute((state, _) => { state.Should().Be("dummy-state"); return result; }, "dummy-state", CancellationToken), result) + { + Caption = "ExecuteT_StateAndCancellation", + AssertContext = AssertResilienceContextAndToken, }; static void AssertResilienceContext(ResilienceContext context) diff --git a/src/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs b/src/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs index 8483f478af5..23ba32f8af5 100644 --- a/src/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs +++ b/src/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs @@ -21,7 +21,7 @@ public void ShouldRetryEmpty_Skipped() SetupNoDelay(); var sut = CreateSut(); - sut.Execute(_ => 0, default); + sut.Execute(() => 0); called.Should().BeFalse(); } @@ -36,7 +36,7 @@ public void Retry_RetryCount_Respected() SetupNoDelay(); var sut = CreateSut(); - sut.Execute(_ => 0, default); + sut.Execute(() => 0); calls.Should().Be(12); } @@ -55,7 +55,7 @@ public void RetryException_RetryCount_Respected() SetupNoDelay(); var sut = CreateSut(); - Assert.Throws(() => sut.Execute(_ => throw new InvalidOperationException(), default)); + Assert.Throws(() => sut.Execute(() => throw new InvalidOperationException())); calls.Should().Be(3); } @@ -79,7 +79,7 @@ public void Retry_Infinite_Respected() SetupNoDelay(); var sut = CreateSut(); - Assert.Throws(() => sut.Execute(_ => 0, default)); + Assert.Throws(() => sut.Execute(() => 0)); calls.Should().Be(RetryConstants.MaxRetryCount + 1); } @@ -97,7 +97,7 @@ public void RetryDelayGenerator_Respected() var sut = CreateSut(); - sut.Execute(_ => 0, default); + sut.Execute(() => 0); _timeProvider.Verify(v => v.Delay(TimeSpan.FromMilliseconds(123), default), Times.Exactly(3)); } @@ -123,7 +123,7 @@ public void OnRetry_EnsureCorrectArguments() var sut = CreateSut(); - sut.Execute(_ => 0, default); + sut.Execute(() => 0); attempts.Should().HaveCount(3); attempts[0].Should().Be(0); @@ -150,7 +150,7 @@ public void OnRetry_EnsureTelemetry() var sut = CreateSut(); - sut.Execute(_ => 0, default); + sut.Execute(() => 0); _diagnosticSource.VerifyAll(); } @@ -178,7 +178,7 @@ public void RetryDelayGenerator_EnsureCorrectArguments() var sut = CreateSut(); - sut.Execute(_ => 0, default); + sut.Execute(() => 0); attempts.Should().HaveCount(3); attempts[0].Should().Be(0); diff --git a/src/Polly.Core/ResilienceStrategy.Async.Task.cs b/src/Polly.Core/ResilienceStrategy.Async.Task.cs index 13687091520..43cf4026076 100644 --- a/src/Polly.Core/ResilienceStrategy.Async.Task.cs +++ b/src/Polly.Core/ResilienceStrategy.Async.Task.cs @@ -33,6 +33,65 @@ static async (context, state) => (callback, state)).ConfigureAwait(context.ContinueOnCapturedContext); } + /// + /// Executes the specified callback. + /// + /// The user-provided callback. + /// The context associated with the callback. + /// The instance of that represents the asynchronous execution. + public async Task ExecuteAsync( + Func callback, + ResilienceContext context) + { + Guard.NotNull(callback); + Guard.NotNull(context); + + InitializeAsyncContext(context); + + await ExecuteCoreAsync( + static async (context, state) => + { + await state(context).ConfigureAwait(context.ContinueOnCapturedContext); + return VoidResult.Instance; + }, + context, + callback).ConfigureAwait(context.ContinueOnCapturedContext); + } + + /// + /// Executes the specified callback. + /// + /// The type of state associated with the callback. + /// The user-provided callback. + /// The state associated with the callback. + /// The associated with the callback. + /// The instance of that represents the asynchronous execution. + public async Task ExecuteAsync( + Func callback, + TState state, + CancellationToken cancellationToken) + { + Guard.NotNull(callback); + + var context = GetAsyncContext(cancellationToken); + + try + { + await ExecuteCoreAsync( + static async (context, state) => + { + await state.callback(state.state, context.CancellationToken).ConfigureAwait(context.ContinueOnCapturedContext); + return VoidResult.Instance; + }, + context, + (callback, state)).ConfigureAwait(context.ContinueOnCapturedContext); + } + finally + { + ResilienceContext.Return(context); + } + } + /// /// Executes the specified callback. /// diff --git a/src/Polly.Core/ResilienceStrategy.Async.TaskT.cs b/src/Polly.Core/ResilienceStrategy.Async.TaskT.cs index 4e9fe1fca79..4e3f42bd915 100644 --- a/src/Polly.Core/ResilienceStrategy.Async.TaskT.cs +++ b/src/Polly.Core/ResilienceStrategy.Async.TaskT.cs @@ -1,3 +1,5 @@ +using System.Threading; + namespace Polly; public abstract partial class ResilienceStrategy @@ -30,6 +32,65 @@ static async (context, state) => (callback, state)).ConfigureAwait(context.ContinueOnCapturedContext); } + /// + /// Executes the specified callback. + /// + /// The type of result returned by the callback. + /// The user-provided callback. + /// The context associated with the callback. + /// The instance of that represents the asynchronous execution. + public async Task ExecuteAsync( + Func> callback, + ResilienceContext context) + { + Guard.NotNull(callback); + Guard.NotNull(context); + + InitializeAsyncContext(context); + + return await ExecuteCoreAsync( + static async (context, state) => + { + return await state(context).ConfigureAwait(context.ContinueOnCapturedContext); + }, + context, + callback).ConfigureAwait(context.ContinueOnCapturedContext); + } + + /// + /// Executes the specified callback. + /// + /// The type of result returned by the callback. + /// The type of state associated with the callback. + /// The user-provided callback. + /// The state associated with the callback. + /// The associated with the callback. + /// The instance of that represents the asynchronous execution. + public async Task ExecuteAsync( + Func> callback, + TState state, + CancellationToken cancellationToken) + { + Guard.NotNull(callback); + + var context = GetAsyncContext(cancellationToken); + + try + { + return await ExecuteCoreAsync( + static async (context, state) => + { + return await state.callback(state.state, context.CancellationToken).ConfigureAwait(context.ContinueOnCapturedContext); + }, + context, + (callback, state)).ConfigureAwait(context.ContinueOnCapturedContext); + } + finally + { + ResilienceContext.Return(context); + } + } + /// /// Executes the specified callback. /// diff --git a/src/Polly.Core/ResilienceStrategy.Async.ValueTask.cs b/src/Polly.Core/ResilienceStrategy.Async.ValueTask.cs index 6e78f39086d..7a3f92d2a1d 100644 --- a/src/Polly.Core/ResilienceStrategy.Async.ValueTask.cs +++ b/src/Polly.Core/ResilienceStrategy.Async.ValueTask.cs @@ -33,6 +33,65 @@ static async (context, state) => (callback, state)).ConfigureAwait(context.ContinueOnCapturedContext); } + /// + /// Executes the specified callback. + /// + /// The user-provided callback. + /// The context associated with the callback. + /// The instance of that represents the asynchronous execution. + public async ValueTask ExecuteValueTaskAsync( + Func callback, + ResilienceContext context) + { + Guard.NotNull(callback); + Guard.NotNull(context); + + InitializeAsyncContext(context); + + await ExecuteCoreAsync( + static async (context, state) => + { + await state(context).ConfigureAwait(context.ContinueOnCapturedContext); + return VoidResult.Instance; + }, + context, + callback).ConfigureAwait(context.ContinueOnCapturedContext); + } + + /// + /// Executes the specified callback. + /// + /// The type of state associated with the callback. + /// The user-provided callback. + /// The state associated with the callback. + /// The associated with the callback. + /// The instance of that represents an asynchronous callback. + public async ValueTask ExecuteValueTaskAsync( + Func callback, + TState state, + CancellationToken cancellationToken = default) + { + Guard.NotNull(callback); + + var context = GetAsyncContext(cancellationToken); + + try + { + await ExecuteCoreAsync( + static async (context, state) => + { + await state.callback(state.state, context.CancellationToken).ConfigureAwait(context.ContinueOnCapturedContext); + return VoidResult.Instance; + }, + context, + (callback, state)).ConfigureAwait(context.ContinueOnCapturedContext); + } + finally + { + ResilienceContext.Return(context); + } + } + /// /// Executes the specified callback. /// diff --git a/src/Polly.Core/ResilienceStrategy.Async.ValueTaskT.cs b/src/Polly.Core/ResilienceStrategy.Async.ValueTaskT.cs index 983f8d89f36..86dcc456379 100644 --- a/src/Polly.Core/ResilienceStrategy.Async.ValueTaskT.cs +++ b/src/Polly.Core/ResilienceStrategy.Async.ValueTaskT.cs @@ -24,6 +24,56 @@ public ValueTask ExecuteValueTaskAsync( return ExecuteCoreAsync(callback, context, state); } + /// + /// Executes the specified callback. + /// + /// The type of result returned by the callback. + /// The user-provided callback. + /// The context associated with the callback. + /// The instance of that represents the asynchronous execution. + public ValueTask ExecuteValueTaskAsync( + Func> callback, + ResilienceContext context) + { + Guard.NotNull(callback); + Guard.NotNull(context); + + InitializeAsyncContext(context); + + return ExecuteCoreAsync(static (context, state) => state(context), context, callback); + } + + /// + /// Executes the specified callback. + /// + /// The type of result returned by the callback. + /// The type of state associated with the callback. + /// The user-provided callback. + /// The state associated with the callback. + /// The associated with the callback. + /// The instance of that represents the asynchronous execution. + public async ValueTask ExecuteValueTaskAsync( + Func> callback, + TState state, + CancellationToken cancellationToken = default) + { + Guard.NotNull(callback); + + var context = GetAsyncContext(cancellationToken); + + try + { + return await ExecuteCoreAsync( + static (context, state) => state.callback(state.state, context.CancellationToken), + context, + (callback, state)).ConfigureAwait(context.ContinueOnCapturedContext); + } + finally + { + ResilienceContext.Return(context); + } + } + /// /// Executes the specified callback. /// diff --git a/src/Polly.Core/ResilienceStrategy.Sync.cs b/src/Polly.Core/ResilienceStrategy.Sync.cs index 90ba1aa8129..a5053a958a6 100644 --- a/src/Polly.Core/ResilienceStrategy.Sync.cs +++ b/src/Polly.Core/ResilienceStrategy.Sync.cs @@ -31,6 +31,63 @@ public void Execute( (callback, state)).GetResult(); } + /// + /// Executes the specified callback. + /// + /// The user-provided callback. + /// The context associated with the callback. + public void Execute( + Action callback, + ResilienceContext context) + { + Guard.NotNull(callback); + Guard.NotNull(context); + + InitializeSyncContext(context); + + ExecuteCoreAsync( + static (context, state) => + { + state(context); + return new ValueTask(VoidResult.Instance); + }, + context, + callback).GetResult(); + } + + /// + /// Executes the specified callback. + /// + /// The type of state associated with the callback. + /// The user-provided callback. + /// The state associated with the callback. + /// The associated with the callback. + public void Execute( + Action callback, + TState state, + CancellationToken cancellationToken = default) + { + Guard.NotNull(callback); + + var context = GetSyncContext(cancellationToken); + + try + { + ExecuteCoreAsync( + static (context, state) => + { + state.callback(state.state, context.CancellationToken); + return new ValueTask(VoidResult.Instance); + }, + context, + (callback, state)).GetResult(); + } + finally + { + ResilienceContext.Return(context); + } + } + /// /// Executes the specified callback. /// @@ -61,6 +118,64 @@ public void Execute( } } + /// + /// Executes the specified callback. + /// + /// The type of state associated with the callback. + /// The user-provided callback. + /// The state associated with the callback. + public void Execute( + Action callback, + TState state) + { + Guard.NotNull(callback); + + var context = GetSyncContext(CancellationToken.None); + + try + { + ExecuteCoreAsync( + static (_, state) => + { + state.callback(state.state); + return new ValueTask(VoidResult.Instance); + }, + context, + (callback, state)).GetResult(); + } + finally + { + ResilienceContext.Return(context); + } + } + + /// + /// Executes the specified callback. + /// + /// The user-provided callback. + public void Execute(Action callback) + { + Guard.NotNull(callback); + + var context = GetSyncContext(CancellationToken.None); + + try + { + ExecuteCoreAsync( + static (_, state) => + { + state(); + return new ValueTask(VoidResult.Instance); + }, + context, + callback).GetResult(); + } + finally + { + ResilienceContext.Return(context); + } + } + private static ResilienceContext GetSyncContext(CancellationToken cancellationToken) => GetSyncContext(cancellationToken); private static void InitializeSyncContext(ResilienceContext context) => InitializeSyncContext(context); diff --git a/src/Polly.Core/ResilienceStrategy.SyncT.cs b/src/Polly.Core/ResilienceStrategy.SyncT.cs index 3102754e6dd..ccffdaa64c4 100644 --- a/src/Polly.Core/ResilienceStrategy.SyncT.cs +++ b/src/Polly.Core/ResilienceStrategy.SyncT.cs @@ -29,6 +29,28 @@ public TResult Execute( (callback, state)).GetResult(); } + /// + /// Executes the specified callback. + /// + /// The type of result returned by the callback. + /// The user-provided callback. + /// The context associated with the callback. + /// An instance of that represents the asynchronous execution. + public TResult Execute( + Func callback, + ResilienceContext context) + { + Guard.NotNull(callback); + Guard.NotNull(context); + + InitializeSyncContext(context); + + return ExecuteCoreAsync( + static (context, state) => new ValueTask(state(context)), + context, + callback).GetResult(); + } + /// /// Executes the specified callback. /// @@ -57,6 +79,89 @@ public TResult Execute( } } + /// + /// Executes the specified callback. + /// + /// The type of result returned by the callback. + /// The user-provided callback. + /// An instance of that represents the asynchronous execution. + public TResult Execute(Func callback) + { + Guard.NotNull(callback); + + var context = GetSyncContext(CancellationToken.None); + + try + { + return ExecuteCoreAsync( + static (_, state) => new ValueTask(state()), + context, + callback).GetResult(); + } + finally + { + ResilienceContext.Return(context); + } + } + + /// + /// Executes the specified callback. + /// + /// The type of result returned by the callback. + /// The type of state associated with the callback. + /// The user-provided callback. + /// The state associated with the callback. + /// An instance of that represents the asynchronous execution. + public TResult Execute(Func callback, TState state) + { + Guard.NotNull(callback); + + var context = GetSyncContext(CancellationToken.None); + + try + { + return ExecuteCoreAsync( + static (_, state) => new ValueTask(state.callback(state.state)), + context, + (callback, state)).GetResult(); + } + finally + { + ResilienceContext.Return(context); + } + } + + /// + /// Executes the specified callback. + /// + /// The type of result returned by the callback. + /// The type of state associated with the callback. + /// The user-provided callback. + /// The state associated with the callback. + /// The associated with the callback. + /// An instance of that represents the asynchronous execution. + public TResult Execute( + Func callback, + TState state, + CancellationToken cancellationToken) + { + Guard.NotNull(callback); + + var context = GetSyncContext(cancellationToken); + + try + { + return ExecuteCoreAsync( + static (context, state) => new ValueTask(state.callback(state.state, context.CancellationToken)), + context, + (callback, state)).GetResult(); + } + finally + { + ResilienceContext.Return(context); + } + } + private static ResilienceContext GetSyncContext(CancellationToken cancellationToken) { var context = ResilienceContext.Get();