Skip to content

Commit

Permalink
Debugger proxies for resilience strategies (#1379)
Browse files Browse the repository at this point in the history
  • Loading branch information
martintmk authored Jul 3, 2023
1 parent 870d053 commit 158a2f8
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 0 deletions.
35 changes: 35 additions & 0 deletions src/Polly.Core/ResilienceStrategy.DebuggerProxy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
namespace Polly;

public abstract partial class ResilienceStrategy
{
internal sealed class DebuggerProxy
{
private readonly ResilienceStrategy _resilienceStrategy;

public DebuggerProxy(ResilienceStrategy resilienceStrategy) => _resilienceStrategy = resilienceStrategy;

[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public IEnumerable<ResilienceStrategy> Strategies => UnwrapStrategies(_resilienceStrategy);

private IEnumerable<ResilienceStrategy> UnwrapStrategies(ResilienceStrategy strategy)
{
if (strategy is ResilienceStrategyPipeline pipeline)
{
return pipeline.Strategies;
}

if (strategy is ReloadableResilienceStrategy reloadableResilienceStrategy)
{
var list = new List<ResilienceStrategy>
{
strategy
};
list.AddRange(UnwrapStrategies(reloadableResilienceStrategy.Strategy));

return list;
}

return new[] { strategy };
}
}
}
3 changes: 3 additions & 0 deletions src/Polly.Core/ResilienceStrategy.TResult.Async.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using Polly.Utils;

namespace Polly;

/// <summary>
Expand All @@ -8,6 +10,7 @@ namespace Polly;
/// Resilience strategy supports various types of callbacks of <typeparamref name="TResult"/> result type
/// and provides a unified way to execute them. This includes overloads for synchronous and asynchronous callbacks.
/// </remarks>
[DebuggerTypeProxy(typeof(ResilienceStrategy<>.DebuggerProxy))]
public partial class ResilienceStrategy<TResult>
{
internal ResilienceStrategy(ResilienceStrategy strategy) => Strategy = strategy;
Expand Down
14 changes: 14 additions & 0 deletions src/Polly.Core/ResilienceStrategy.TResult.DebuggerProxy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace Polly;

public partial class ResilienceStrategy<TResult>
{
internal sealed class DebuggerProxy
{
private readonly ResilienceStrategy.DebuggerProxy _proxy;

public DebuggerProxy(ResilienceStrategy<TResult> strategy) => _proxy = new ResilienceStrategy.DebuggerProxy(strategy.Strategy);

[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public IEnumerable<ResilienceStrategy> Strategies => _proxy.Strategies;
}
}
1 change: 1 addition & 0 deletions src/Polly.Core/ResilienceStrategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace Polly;
/// Resilience strategy supports various types of callbacks and provides a unified way to execute them.
/// This includes overloads for synchronous and asynchronous callbacks, generic and non-generic callbacks.
/// </remarks>
[DebuggerTypeProxy(typeof(DebuggerProxy))]
public abstract partial class ResilienceStrategy
{
/// <summary>
Expand Down
3 changes: 3 additions & 0 deletions src/Polly.Core/Utils/ResilienceStrategyPipeline.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
using System.Diagnostics;

namespace Polly.Utils;

#pragma warning disable S2302 // "nameof" should be used

/// <summary>
/// A pipeline of strategies.
/// </summary>
[DebuggerDisplay("ResilienceStrategyPipeline, Strategies = {Strategies.Count}")]
internal sealed class ResilienceStrategyPipeline : ResilienceStrategy
{
private readonly ResilienceStrategy _pipeline;
Expand Down
19 changes: 19 additions & 0 deletions test/Polly.Core.Tests/ResilienceStrategyTests.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
using Moq;
using Polly.Utils;

namespace Polly.Core.Tests;

public partial class ResilienceStrategyTests
Expand Down Expand Up @@ -28,6 +31,22 @@ await TestUtilities.AssertWithTimeoutAsync(async () =>
});
}

[Fact]
public void DebuggerProxy_Ok()
{
var pipeline = ResilienceStrategyPipeline.CreatePipeline(new[]
{
new TestResilienceStrategy(),
new TestResilienceStrategy()
});
var reloadable = new ReloadableResilienceStrategy(pipeline, () => default, () => pipeline, TestUtilities.CreateResilienceTelemetry(Mock.Of<DiagnosticSource>()));

new ResilienceStrategy.DebuggerProxy(NullResilienceStrategy.Instance).Strategies.Should().HaveCount(1);
new ResilienceStrategy.DebuggerProxy(pipeline).Strategies.Should().HaveCount(2);
new ResilienceStrategy.DebuggerProxy(reloadable).Strategies.Should().HaveCount(3);
new ResilienceStrategy<string>.DebuggerProxy(NullResilienceStrategy<string>.Instance).Strategies.Should().HaveCount(1);
}

public class ExecuteParameters<T> : ExecuteParameters
{
public ExecuteParameters(Func<ResilienceStrategy, Task<T>> execute, T resultValue)
Expand Down

0 comments on commit 158a2f8

Please sign in to comment.