diff --git a/src/Polly.Core/Registry/RegistryPipelineComponentBuilder.cs b/src/Polly.Core/Registry/RegistryPipelineComponentBuilder.cs new file mode 100644 index 0000000000..fc4bf8a0a1 --- /dev/null +++ b/src/Polly.Core/Registry/RegistryPipelineComponentBuilder.cs @@ -0,0 +1,72 @@ +using Polly.Telemetry; +using Polly.Utils.Pipeline; + +namespace Polly.Registry; + +/// +/// Builds a used by the registry. +/// +internal class RegistryPipelineComponentBuilder + where TBuilder : ResiliencePipelineBuilderBase + where TKey : notnull +{ + private readonly Func _activator; + private readonly TKey _key; + private readonly string _builderName; + private readonly string? _instanceName; + private readonly Action> _configure; + + public RegistryPipelineComponentBuilder( + Func activator, + TKey key, + string builderName, + string? instanceName, + Action> configure) + { + _activator = activator; + _key = key; + _builderName = builderName; + _instanceName = instanceName; + _configure = configure; + } + + internal PipelineComponent CreateComponent() + { + var builder = CreateBuilder(); + var telemetry = new ResilienceStrategyTelemetry( + new ResilienceTelemetrySource(_builderName, _instanceName, null), + builder.Listener); + + var initialPipeline = builder.ComponentFactory(); + + if (builder.ReloadTokenProducer is null) + { + return initialPipeline; + } + + return PipelineComponentFactory.CreateReloadable( + initialPipeline, + builder.ReloadTokenProducer(), + () => CreateBuilder().ComponentFactory(), + telemetry); + } + + private Builder CreateBuilder() + { + var context = new ConfigureBuilderContext(_key, _builderName, _instanceName); + var builder = _activator(); + builder.Name = _builderName; + builder.InstanceName = _instanceName; + _configure(builder, context); + + return new( + builder.BuildPipelineComponent, + context.ReloadTokenProducer, + builder.TelemetryListener); + } + + private record Builder( + Func ComponentFactory, + Func>? ReloadTokenProducer, + TelemetryListener? Listener); +} diff --git a/src/Polly.Core/Registry/ResiliencePipelineRegistry.TResult.cs b/src/Polly.Core/Registry/ResiliencePipelineRegistry.TResult.cs index bb19b8e582..627553faea 100644 --- a/src/Polly.Core/Registry/ResiliencePipelineRegistry.TResult.cs +++ b/src/Polly.Core/Registry/ResiliencePipelineRegistry.TResult.cs @@ -49,13 +49,17 @@ public ResiliencePipeline GetOrAdd(TKey key, Action(key, _builderNameFormatter(key), _instanceNameFormatter?.Invoke(key)); - return _pipelines.GetOrAdd(key, static (_, factory) => + return _pipelines.GetOrAdd(key, k => { - var component = CreatePipelineComponent(factory.instance._activator, factory.context, factory.configure); + var component = new RegistryPipelineComponentBuilder, TKey>( + _activator, + k, + _builderNameFormatter(k), + _instanceNameFormatter?.Invoke(k), + configure).CreateComponent(); return new ResiliencePipeline(component, DisposeBehavior.Reject); - }, - (instance: this, context, configure)); + }); } public bool TryAddBuilder(TKey key, Action, ConfigureBuilderContext> configure) => _builders.TryAdd(key, configure); diff --git a/src/Polly.Core/Registry/ResiliencePipelineRegistry.cs b/src/Polly.Core/Registry/ResiliencePipelineRegistry.cs index 6b1c579da3..27f26fcc0e 100644 --- a/src/Polly.Core/Registry/ResiliencePipelineRegistry.cs +++ b/src/Polly.Core/Registry/ResiliencePipelineRegistry.cs @@ -1,6 +1,5 @@ using System.ComponentModel.DataAnnotations; using System.Diagnostics.CodeAnalysis; -using Polly.Telemetry; using Polly.Utils.Pipeline; namespace Polly.Registry; @@ -124,15 +123,17 @@ public ResiliencePipeline GetOrAddPipeline(TKey key, Action(key, _builderNameFormatter(key), _instanceNameFormatter?.Invoke(key)); - - return _pipelines.GetOrAdd(key, static (_, factory) => + return _pipelines.GetOrAdd(key, k => { - var component = CreatePipelineComponent(factory.instance._activator, factory.context, factory.configure); + var component = new RegistryPipelineComponentBuilder( + _activator, + k, + _builderNameFormatter(k), + _instanceNameFormatter?.Invoke(k), + configure).CreateComponent(); return new ResiliencePipeline(component, DisposeBehavior.Reject); - }, - (instance: this, context, configure)); + }); } /// @@ -260,36 +261,6 @@ public async ValueTask DisposeAsync() } } - private static PipelineComponent CreatePipelineComponent( - Func activator, - ConfigureBuilderContext context, - Action> configure) - where TBuilder : ResiliencePipelineBuilderBase - { - Func factory = () => - { - var builder = activator(); - builder.Name = context.BuilderName; - builder.InstanceName = context.BuilderInstanceName; - configure(builder, context); - - return builder; - }; - - var builder = factory(); - var pipeline = builder.BuildPipelineComponent(); - var telemetry = new ResilienceStrategyTelemetry( - new ResilienceTelemetrySource(context.BuilderName, context.BuilderInstanceName, null), - builder.TelemetryListener); - - if (context.ReloadTokenProducer is null) - { - return pipeline; - } - - return PipelineComponentFactory.CreateReloadable(pipeline, context.ReloadTokenProducer(), () => factory().BuildPipelineComponent(), telemetry); - } - private GenericRegistry GetGenericRegistry() { if (_genericRegistry.TryGetValue(typeof(TResult), out var genericRegistry))