diff --git a/src/Polly.Core/PublicAPI.Unshipped.txt b/src/Polly.Core/PublicAPI.Unshipped.txt index 21122acf546..37351e7da91 100644 --- a/src/Polly.Core/PublicAPI.Unshipped.txt +++ b/src/Polly.Core/PublicAPI.Unshipped.txt @@ -1,7 +1,7 @@ #nullable enable abstract Polly.Registry.ResiliencePipelineProvider.TryGetPipeline(TKey key, out Polly.ResiliencePipeline? pipeline) -> bool abstract Polly.Registry.ResiliencePipelineProvider.TryGetPipeline(TKey key, out Polly.ResiliencePipeline? pipeline) -> bool -abstract Polly.ResilienceContextPool.Get(string? operationKey, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Polly.ResilienceContext! +abstract Polly.ResilienceContextPool.Get(Polly.ResilienceContextCreationArguments arguments) -> Polly.ResilienceContext! abstract Polly.ResilienceContextPool.Return(Polly.ResilienceContext! context) -> void abstract Polly.ResilienceStrategy.ExecuteCore(System.Func>>! callback, Polly.ResilienceContext! context, TState state) -> System.Threading.Tasks.ValueTask> abstract Polly.ResilienceStrategy.ExecuteCore(System.Func>>! callback, Polly.ResilienceContext! context, TState state) -> System.Threading.Tasks.ValueTask> @@ -198,12 +198,20 @@ Polly.Registry.ResiliencePipelineRegistryOptions.ResiliencePipelineRegistr Polly.ResilienceContext Polly.ResilienceContext.CancellationToken.get -> System.Threading.CancellationToken Polly.ResilienceContext.ContinueOnCapturedContext.get -> bool -Polly.ResilienceContext.ContinueOnCapturedContext.set -> void Polly.ResilienceContext.IsSynchronous.get -> bool Polly.ResilienceContext.OperationKey.get -> string? Polly.ResilienceContext.Properties.get -> Polly.ResilienceProperties! Polly.ResilienceContext.ResilienceEvents.get -> System.Collections.Generic.IReadOnlyList! +Polly.ResilienceContextCreationArguments +Polly.ResilienceContextCreationArguments.CancellationToken.get -> System.Threading.CancellationToken +Polly.ResilienceContextCreationArguments.ContinueOnCapturedContext.get -> bool? +Polly.ResilienceContextCreationArguments.OperationKey.get -> string? +Polly.ResilienceContextCreationArguments.ResilienceContextCreationArguments() -> void +Polly.ResilienceContextCreationArguments.ResilienceContextCreationArguments(string? operationKey, bool? continueOnCapturedContext, System.Threading.CancellationToken cancellationToken) -> void Polly.ResilienceContextPool +Polly.ResilienceContextPool.Get(bool continueOnCapturedContext, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Polly.ResilienceContext! +Polly.ResilienceContextPool.Get(string? operationKey, bool? continueOnCapturedContext, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Polly.ResilienceContext! +Polly.ResilienceContextPool.Get(string? operationKey, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Polly.ResilienceContext! Polly.ResilienceContextPool.Get(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Polly.ResilienceContext! Polly.ResilienceContextPool.ResilienceContextPool() -> void Polly.ResiliencePipeline diff --git a/src/Polly.Core/ResilienceContext.cs b/src/Polly.Core/ResilienceContext.cs index ac7ca5473ce..e02970b69f3 100644 --- a/src/Polly.Core/ResilienceContext.cs +++ b/src/Polly.Core/ResilienceContext.cs @@ -14,8 +14,6 @@ namespace Polly; /// public sealed class ResilienceContext { - private const bool ContinueOnCapturedContextDefault = false; - private readonly List _resilienceEvents = new(); internal ResilienceContext() @@ -54,9 +52,9 @@ internal ResilienceContext() internal bool IsVoid => ResultType == typeof(VoidResult); /// - /// Gets or sets a value indicating whether the execution should continue on the captured context. + /// Gets a value indicating whether the execution should continue on the captured context. /// - public bool ContinueOnCapturedContext { get; set; } + public bool ContinueOnCapturedContext { get; internal set; } /// /// Gets a value indicating whether the context is initialized. @@ -98,7 +96,6 @@ internal ResilienceContext Initialize(bool isSynchronous) { IsSynchronous = isSynchronous; ResultType = typeof(TResult); - ContinueOnCapturedContext = ContinueOnCapturedContextDefault; return this; } diff --git a/src/Polly.Core/ResilienceContextCreationArguments.cs b/src/Polly.Core/ResilienceContextCreationArguments.cs new file mode 100644 index 00000000000..9fb5190332c --- /dev/null +++ b/src/Polly.Core/ResilienceContextCreationArguments.cs @@ -0,0 +1,37 @@ +namespace Polly; + +#pragma warning disable CA1815 // Override equals and operator equals on value types + +/// +/// Arguments used by the when creating . +/// +public readonly struct ResilienceContextCreationArguments +{ + /// + /// Initializes a new instance of the struct. + /// + /// The operation key, if any. + /// Value indicating whether to continue on captured context. + /// The cancellation token. + public ResilienceContextCreationArguments(string? operationKey, bool? continueOnCapturedContext, CancellationToken cancellationToken) + { + OperationKey = operationKey; + ContinueOnCapturedContext = continueOnCapturedContext; + CancellationToken = cancellationToken; + } + + /// + /// Gets the operation key, if any. + /// + public string? OperationKey { get; } + + /// + /// Gets the value indicating whether to continue on captured context, if any. + /// + public bool? ContinueOnCapturedContext { get; } + + /// + /// Gets the cancellation token. + /// + public CancellationToken CancellationToken { get; } +} diff --git a/src/Polly.Core/ResilienceContextPool.Shared.cs b/src/Polly.Core/ResilienceContextPool.Shared.cs index ca3ef4590e7..68c1c51545a 100644 --- a/src/Polly.Core/ResilienceContextPool.Shared.cs +++ b/src/Polly.Core/ResilienceContextPool.Shared.cs @@ -2,16 +2,19 @@ public abstract partial class ResilienceContextPool { + private const bool ContinueOnCapturedContextDefault = false; + private sealed class SharedPool : ResilienceContextPool { private readonly ObjectPool _pool = new(static () => new ResilienceContext(), static c => c.Reset()); - public override ResilienceContext Get(string? operationKey, CancellationToken cancellationToken = default) + public override ResilienceContext Get(ResilienceContextCreationArguments arguments) { var context = _pool.Get(); - context.OperationKey = operationKey; - context.CancellationToken = cancellationToken; + context.OperationKey = arguments.OperationKey; + context.CancellationToken = arguments.CancellationToken; + context.ContinueOnCapturedContext = arguments.ContinueOnCapturedContext ?? ContinueOnCapturedContextDefault; return context; } diff --git a/src/Polly.Core/ResilienceContextPool.cs b/src/Polly.Core/ResilienceContextPool.cs index d0eb38efd7b..d9d8edef047 100644 --- a/src/Polly.Core/ResilienceContextPool.cs +++ b/src/Polly.Core/ResilienceContextPool.cs @@ -1,7 +1,7 @@ namespace Polly; -#pragma warning disable CA1716 // Identifiers should not match keywords #pragma warning disable RS0026 // Do not add multiple public overloads with optional parameters +#pragma warning disable CA1716 // Identifiers should not match keywords /// /// The pool of instances. @@ -34,7 +34,45 @@ public abstract partial class ResilienceContextPool /// After the execution is finished you should return the back to the pool /// by calling method. /// - public abstract ResilienceContext Get(string? operationKey, CancellationToken cancellationToken = default); + public ResilienceContext Get(string? operationKey, CancellationToken cancellationToken = default) => Get(operationKey, null, cancellationToken); + + /// + /// Gets a instance from the pool. + /// + /// An operation key associated with the context. + /// Value indicating whether to continue on captured context. + /// The cancellation token. + /// An instance of . + /// + /// After the execution is finished you should return the back to the pool + /// by calling method. + /// + public ResilienceContext Get(string? operationKey, bool? continueOnCapturedContext, CancellationToken cancellationToken = default) + => Get(new ResilienceContextCreationArguments(operationKey, continueOnCapturedContext, cancellationToken)); + + /// + /// Gets a instance from the pool. + /// + /// Value indicating whether to continue on captured context. + /// The cancellation token. + /// An instance of . + /// + /// After the execution is finished you should return the back to the pool + /// by calling method. + /// + public ResilienceContext Get(bool continueOnCapturedContext, CancellationToken cancellationToken = default) + => Get(new ResilienceContextCreationArguments(null, continueOnCapturedContext, cancellationToken)); + + /// + /// Gets a instance from the pool. + /// + /// The creation arguments. + /// An instance of . + /// + /// After the execution is finished you should return the back to the pool + /// by calling method. + /// + public abstract ResilienceContext Get(ResilienceContextCreationArguments arguments); /// /// Returns a back to the pool. diff --git a/src/Polly/Utilities/Wrappers/ResilienceContextFactory.cs b/src/Polly/Utilities/Wrappers/ResilienceContextFactory.cs index f2b46a81309..b334db5c584 100644 --- a/src/Polly/Utilities/Wrappers/ResilienceContextFactory.cs +++ b/src/Polly/Utilities/Wrappers/ResilienceContextFactory.cs @@ -8,8 +8,7 @@ public static ResilienceContext Create( bool continueOnCapturedContext, out IDictionary oldProperties) { - var resilienceContext = ResilienceContextPool.Shared.Get(context.OperationKey, cancellationToken); - resilienceContext.ContinueOnCapturedContext = continueOnCapturedContext; + var resilienceContext = ResilienceContextPool.Shared.Get(context.OperationKey, continueOnCapturedContext, cancellationToken); resilienceContext.Properties.SetProperties(context, out oldProperties); return resilienceContext; diff --git a/test/Polly.Core.Tests/ResilienceContextPoolTests.cs b/test/Polly.Core.Tests/ResilienceContextPoolTests.cs index b9a052efab9..5f0da0f73f6 100644 --- a/test/Polly.Core.Tests/ResilienceContextPoolTests.cs +++ b/test/Polly.Core.Tests/ResilienceContextPoolTests.cs @@ -40,6 +40,36 @@ public void Get_CancellationToken_Ok() context.CancellationToken.Should().Be(token.Token); } + [Fact] + public void Get_ContinueOnCapturedContextDefault_ShouldBeFalse() + { + using var token = new CancellationTokenSource(); + + var context = ResilienceContextPool.Shared.Get(); + + context.ContinueOnCapturedContext.Should().BeFalse(); + } + + [Fact] + public void Get_ContinueOnCapturedContext_Ok() + { + var context = ResilienceContextPool.Shared.Get(true); + + context.ContinueOnCapturedContext.Should().Be(true); + } + + [Fact] + public void Get_OperationKeyContinueOnCapturedContext_Ok() + { + using var token = new CancellationTokenSource(); + + var context = ResilienceContextPool.Shared.Get("dummy", true, token.Token); + + context.ContinueOnCapturedContext.Should().Be(true); + context.OperationKey.Should().Be("dummy"); + context.CancellationToken.Should().Be(token.Token); + } + [InlineData(null)] [InlineData("")] [InlineData("some-key")]