Skip to content

Commit

Permalink
Use Polly resilience pipelines
Browse files Browse the repository at this point in the history
Update the Polly samples to use the new Polly v8 APIs.
  • Loading branch information
martincostello committed Nov 1, 2023
1 parent fa6a684 commit 4700d9b
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 28 deletions.
2 changes: 1 addition & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<PackageVersion Include="MinVer" Version="4.3.0" />
<PackageVersion Include="morelinq" Version="4.0.0" />
<PackageVersion Include="NSubstitute" Version="5.1.0" />
<PackageVersion Include="Polly" Version="8.1.0" />
<PackageVersion Include="Polly.Core" Version="8.1.0" />
<PackageVersion Include="ReportGenerator" Version="5.1.26" />
<PackageVersion Include="Serilog" Version="3.0.1" />
<PackageVersion Include="Serilog.AspNetCore" Version="7.0.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<PackageReference Include="Microsoft.Extensions.Configuration.Json" />
<PackageReference Include="Microsoft.Extensions.Hosting" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
<PackageReference Include="Polly" />
<PackageReference Include="Polly.Core" />
<PackageReference Include="Serilog.AspNetCore" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using JustSaying.Messaging.Middleware;
using JustSaying.Messaging.Middleware;
using JustSaying.Sample.Middleware.Exceptions;
using Polly;
using Polly.Retry;
using Serilog;

namespace JustSaying.Sample.Middleware.Middlewares;
Expand All @@ -10,11 +11,11 @@ namespace JustSaying.Sample.Middleware.Middlewares;
/// </summary>
public class PollyJustSayingMiddleware : MiddlewareBase<HandleMessageContext, bool>
{
private readonly AsyncPolicy _policy;
private readonly ResiliencePipeline _pipeline;

public PollyJustSayingMiddleware()
{
_policy = CreateMessageRetryPolicy();
_pipeline = CreateResiliencePipeline();
}

protected override async Task<bool> RunInnerAsync(HandleMessageContext context, Func<CancellationToken, Task<bool>> func, CancellationToken stoppingToken)
Expand All @@ -23,18 +24,41 @@ protected override async Task<bool> RunInnerAsync(HandleMessageContext context,

try
{
return await _policy.ExecuteAsync(func, stoppingToken);
var pool = ResilienceContextPool.Shared;
var resilienceContext = pool.Get(stoppingToken);

try
{
return await _pipeline.ExecuteAsync(
static async (context, func) =>
await func(context.CancellationToken), resilienceContext, func);
}
finally
{
pool.Return(resilienceContext);
}
}
finally
{
Log.Information("[{MiddlewareName}] Finished {MessageType}", nameof(PollyJustSayingMiddleware), context.Message.GetType().Name);
}
}

private static AsyncPolicy CreateMessageRetryPolicy()
private static ResiliencePipeline CreateResiliencePipeline()
{
return Policy.Handle<BusinessException>()
.WaitAndRetryAsync(3, count => TimeSpan.FromMilliseconds(Math.Max(count * 100, 1000)),
onRetry: (e, ts, retryCount, ctx) => Log.Information(e, "Retrying failed operation on count {RetryCount}", retryCount));
return new ResiliencePipelineBuilder()
.AddRetry(new RetryStrategyOptions
{
ShouldHandle = new PredicateBuilder().Handle<BusinessException>(),
Delay = TimeSpan.FromSeconds(1),
MaxRetryAttempts = 3,
BackoffType = DelayBackoffType.Exponential,
OnRetry = (args) =>
{
Log.Information("Retrying failed operation on count {RetryCount}", args.AttemptNumber);
return ValueTask.CompletedTask;
}
})
.Build();
}
}
4 changes: 2 additions & 2 deletions src/JustSaying.Tools/JustSaying.Tools.csproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net461</TargetFramework>
<TargetFramework>net471</TargetFramework>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion tests/JustSaying.UnitTests/JustSaying.UnitTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<PackageReference Include="MELT" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="Newtonsoft.Json" />
<PackageReference Include="Polly" />
<PackageReference Include="Polly.Core" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.runner.visualstudio" />
</ItemGroup>
Expand Down
23 changes: 13 additions & 10 deletions tests/JustSaying.UnitTests/Messaging/Policies/CanCreatePolicy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,27 +45,30 @@ public async Task MiddlewareBuilder_Error_Handler_Async()
[Fact]
public async Task Can_Integrate_With_Polly_Policies_Async()
{
var pollyPolicy = Policy
.Handle<CustomException>()
.CircuitBreakerAsync(
exceptionsAllowedBeforeBreaking: 2,
durationOfBreak: TimeSpan.FromSeconds(1));
var pipeline = new ResiliencePipelineBuilder()
.AddCircuitBreaker(new CircuitBreakerStrategyOptions
{
ShouldHandle = new PredicateBuilder().Handle<CustomException>(),
MinimumThroughput = 2,
BreakDuration = TimeSpan.FromSeconds(1),
})
.Build();

var policy = MiddlewareBuilder.BuildAsync(
new PollyMiddleware<string, int>(pollyPolicy));
var middleware = MiddlewareBuilder.BuildAsync(
new PollyMiddleware<string, int>(pipeline));

var calledCount = 0;
await Assert.ThrowsAsync<CustomException>(() => policy.RunAsync("context", ct =>
await Assert.ThrowsAsync<CustomException>(() => middleware.RunAsync("context", ct =>
{
calledCount++;
throw new CustomException();
}, CancellationToken.None));
await Assert.ThrowsAsync<CustomException>(() => policy.RunAsync("context", ct =>
await Assert.ThrowsAsync<CustomException>(() => middleware.RunAsync("context", ct =>
{
calledCount++;
throw new CustomException();
}, CancellationToken.None));
await Assert.ThrowsAsync<BrokenCircuitException>(() => policy.RunAsync("context", ct =>
await Assert.ThrowsAsync<BrokenCircuitException>(() => middleware.RunAsync("context", ct =>
{
calledCount++;
throw new CustomException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,30 @@ namespace JustSaying.UnitTests.Messaging.Policies.ExamplePolicies;

public class PollyMiddleware<TContext, TOut> : MiddlewareBase<TContext, TOut>
{
private readonly IAsyncPolicy _policy;
private readonly ResiliencePipeline _pipeline;

public PollyMiddleware(IAsyncPolicy policy)
public PollyMiddleware(ResiliencePipeline pipeline)
{
_policy = policy;
_pipeline = pipeline;
}

protected override async Task<TOut> RunInnerAsync(
TContext context,
Func<CancellationToken, Task<TOut>> func,
CancellationToken stoppingToken)
{
return await _policy.ExecuteAsync(() => func(stoppingToken));
var pool = ResilienceContextPool.Shared;
var resilienceContext = pool.Get(stoppingToken);

try
{
return await _pipeline.ExecuteAsync(
static async (context, func) =>
await func(context.CancellationToken), resilienceContext, func);
}
finally
{
pool.Return(resilienceContext);
}
}
}
}

0 comments on commit 4700d9b

Please sign in to comment.