Skip to content

Commit

Permalink
ResilienceStrategyRegistry now also uses BuilderName (#1175)
Browse files Browse the repository at this point in the history
  • Loading branch information
martintmk authored May 3, 2023
1 parent 5765ea3 commit 97a1c55
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@ public void Ctor_EnsureDefaults()
{
ResilienceStrategyRegistryOptions<object> options = new();

options.KeyFormatter.Should().NotBeNull();
options.KeyFormatter(null!).Should().Be("");
options.KeyFormatter("ABC").Should().Be("ABC");
options.StrategyKeyFormatter.Should().NotBeNull();
options.StrategyKeyFormatter(null!).Should().Be("");
options.StrategyKeyFormatter("ABC").Should().Be("ABC");

options.BuilderNameFormatter.Should().NotBeNull();
options.BuilderNameFormatter(null!).Should().Be("");
options.BuilderNameFormatter("ABC").Should().Be("ABC");
}
}
35 changes: 21 additions & 14 deletions src/Polly.Core.Tests/Registry/ResilienceStrategyRegistryTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,22 @@ namespace Polly.Core.Tests.Registry;

public class ResilienceStrategyRegistryTests
{
private readonly ResilienceStrategyRegistryOptions<StrategyId> _options;

private Action<ResilienceStrategyBuilder> _callback = _ => { };

public ResilienceStrategyRegistryTests() => _options = new()
{
BuilderFactory = () =>
{
var builder = new ResilienceStrategyBuilder();
_callback(builder);
return builder;
},
StrategyComparer = StrategyId.Comparer,
BuilderComparer = StrategyId.BuilderComparer
};

[Fact]
public void Ctor_Default_Ok()
{
Expand Down Expand Up @@ -121,18 +135,21 @@ public void AddBuilder_GetStrategy_EnsureCalled()
[Fact]
public void AddBuilder_EnsureStrategyKey()
{
_options.BuilderNameFormatter = k => k.BuilderName;
_options.StrategyKeyFormatter = k => k.InstanceName;

var called = false;
var registry = CreateRegistry();
registry.TryAddBuilder(StrategyId.Create("A"), (key, builder) =>
registry.TryAddBuilder(StrategyId.Create("A"), (_, builder) =>
{
builder.AddStrategy(new TestResilienceStrategy());
builder.BuilderName.Should().Be("A");
builder.Properties.TryGetValue(TelemetryUtil.StrategyKey, out var val).Should().BeTrue();
val.Should().Be(key.ToString());
val.Should().Be("Instance1");
called = true;
});

registry.Get(StrategyId.Create("A", "Instance1"));

called.Should().BeTrue();
}

Expand Down Expand Up @@ -175,16 +192,6 @@ public void TryAdd_Twice_SecondNotAdded()

private ResilienceStrategyRegistry<StrategyId> CreateRegistry()
{
return new ResilienceStrategyRegistry<StrategyId>(new ResilienceStrategyRegistryOptions<StrategyId>
{
BuilderFactory = () =>
{
var builder = new ResilienceStrategyBuilder();
_callback(builder);
return builder;
},
StrategyComparer = StrategyId.Comparer,
BuilderComparer = StrategyId.BuilderComparer
});
return new ResilienceStrategyRegistry<StrategyId>(_options);
}
}
9 changes: 6 additions & 3 deletions src/Polly.Core/Registry/ResilienceStrategyRegistry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ public sealed class ResilienceStrategyRegistry<TKey> : ResilienceStrategyProvide
private readonly Func<ResilienceStrategyBuilder> _activator;
private readonly ConcurrentDictionary<TKey, Action<TKey, ResilienceStrategyBuilder>> _builders;
private readonly ConcurrentDictionary<TKey, ResilienceStrategy> _strategies;
private readonly Func<TKey, string> _keyFormatter;
private readonly Func<TKey, string> _strategyKeyFormatter;
private readonly Func<TKey, string> _builderNameFormatter;

/// <summary>
/// Initializes a new instance of the <see cref="ResilienceStrategyRegistry{TKey}"/> class with the default comparer.
Expand All @@ -44,7 +45,8 @@ public ResilienceStrategyRegistry(ResilienceStrategyRegistryOptions<TKey> option
_activator = options.BuilderFactory;
_builders = new ConcurrentDictionary<TKey, Action<TKey, ResilienceStrategyBuilder>>(options.BuilderComparer);
_strategies = new ConcurrentDictionary<TKey, ResilienceStrategy>(options.StrategyComparer);
_keyFormatter = options.KeyFormatter;
_strategyKeyFormatter = options.StrategyKeyFormatter;
_builderNameFormatter = options.BuilderNameFormatter;
}

/// <summary>
Expand Down Expand Up @@ -89,7 +91,8 @@ public override bool TryGet(TKey key, [NotNullWhen(true)] out ResilienceStrategy
strategy = _strategies.GetOrAdd(key, key =>
{
var builder = _activator();
builder.Properties.Set(TelemetryUtil.StrategyKey, _keyFormatter(key));
builder.BuilderName = _builderNameFormatter(key);
builder.Properties.Set(TelemetryUtil.StrategyKey, _strategyKeyFormatter(key));
configure(key, builder);
return builder.Build();
});
Expand Down
26 changes: 24 additions & 2 deletions src/Polly.Core/Registry/ResilienceStrategyRegistryOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,30 @@ public class ResilienceStrategyRegistryOptions<TKey>
public IEqualityComparer<TKey> BuilderComparer { get; set; } = EqualityComparer<TKey>.Default;

/// <summary>
/// Gets or sets the formatter that is used by the registry to format the keys as a string.
/// Gets or sets the formatter that is used by the registry to format the <typeparamref name="TKey"/> to a string that
/// represents the strategy key.
/// </summary>
/// <remarks>
/// By default, the formatter uses the <see cref="object.ToString"/> method.
/// <para>
/// Use custom formatter for composite keys in case you want to have different metric values for a builder and strategy key.
/// In general, strategies can have the same builder name and different strategy keys.
/// </para>
/// </remarks>
[Required]
public Func<TKey, string> StrategyKeyFormatter { get; set; } = (key) => key?.ToString() ?? string.Empty;

/// <summary>
/// Gets or sets the formatter that is used by the registry to format the <typeparamref name="TKey"/> to a string that
/// represents the builder name.
/// </summary>
/// <remarks>
/// By default, the formatter uses the <see cref="object.ToString"/> method.
/// <para>
/// Use custom formatter for composite keys in case you want to have different metric values for a builder and strategy key.
/// In general, strategies can have the same builder name and different strategy keys.
/// </para>
/// </remarks>
[Required]
public Func<TKey, string> KeyFormatter { get; set; } = (key) => key?.ToString() ?? string.Empty;
public Func<TKey, string> BuilderNameFormatter { get; set; } = (key) => key?.ToString() ?? string.Empty;
}

0 comments on commit 97a1c55

Please sign in to comment.