Skip to content

Instantly share code, notes, and snippets.

@MovGP0
Last active August 31, 2018 06:59
Show Gist options
  • Select an option

  • Save MovGP0/b50b138f8372c6ecba7b55157631e40d to your computer and use it in GitHub Desktop.

Select an option

Save MovGP0/b50b138f8372c6ecba7b55157631e40d to your computer and use it in GitHub Desktop.
Using Polly for Retry Policies

How to enable Polly in an ASP.NET Core 2.0 Application

using Polly;
using Polly.Registry;
namespace MyApp.MyComponent
{
public sealed class MyService : IMyService
{
private static Serilog.ILogger Log => Serilog.Log.ForContext<MyService>();
public GetResource2MaximumParticipantsUoW(IReadOnlyPolicyRegistry<string> policyRegistry)
{
Policy = policyRegistry.GetAsyncPolicy<List<Resource2MaximumParticipants>>(PolicyNames.GetResource2MaximumParticipantsUoW);
}
private IAsyncPolicy<List<Resource2MaximumParticipants>> Policy { get; }
public Task ExecuteAsync(CancellationToken cancellationToken)
{
var context = new Context(nameof(MyService));
// context["hash"] = parameter.GetHash();
return Policy.ExecuteAsync(_ => ExecuteInternalAsync(cancellationToken), context);
}
public Task ExecuteInternalAsync(CancellationToken cancellationToken)
{
//TODO: implement business logic here...
}
}
}
using Polly;
using Polly.Caching;
using Polly.Registry;
namespace MyApp.MyComponent
{
public static class Policies
{
public static IPolicyRegistry<string> AddMyComponentPolicies(this IPolicyRegistry<string> registry, IServiceProvider serviceProvider)
{
var acp = serviceProvider.GetRequiredService<IAsyncCacheProvider>();
registry.Add(PolicyNames.MyService, Create_MyService_Policy(acp));
// TODO: register further policies here
return registry;
}
private static IAsyncPolicy<TResult> Create_MyService_Policy<TResult>(IAsyncCacheProvider acp)
{
var fallback = Policy.NoOpAsync<TResult>();
var cache = Policy
.CacheAsync<TResult>(acp, cacheDuration, context => context.OperationKey + context["hash"]);
var retry = Policy
.Handle<DbUpdateConcurrencyException>()
.RetryAsync();
var breaker = Policy
.Handle<DbUpdateConcurrencyException>()
.AdvancedCircuitBreakerAsync(0.5, TimeSpan.FromSeconds(5), 20, TimeSpan.FromSeconds(30));
var bulkhead = Policy.BulkheadAsync<TResult>(12, 2);
var timeout = Policy.TimeoutAsync<TResult>(TimeSpan.FromSeconds(5));
// must be in this exact order!
return fallback.WrapAsync(cache).WrapAsync(retry).WrapAsync(breaker).WrapAsync(bulkhead).WrapAsync(timeout);
}
}
}
using Microsoft.Extensions.DependencyInjection;
using Polly.Caching;
using Polly.Caching.Memory;
using Polly.Registry;
namespace MyApp
{
public static class PolicyFactory
{
public static IServiceCollection AddPolicies(this IServiceCollection services)
{
services.AddSingleton<IAsyncCacheProvider, MemoryCacheProvider>();
services.AddSingleton<IPolicyRegistry<string>, PolicyRegistry>(serviceProvider =>
{
var registry = new PolicyRegistry();
registry.AddMyComponentPolicies(serviceProvider);
// TODO: register additional components here
return registry;
});
services.AddTransient<IReadOnlyPolicyRegistry<string>>(e => e.GetRequiredService<IPolicyRegistry<string>>());
return services;
}
}
}
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using Polly;
using Polly.Registry;
namespace MyApp
{
public static class PolicyRegistryExtensions
{
private static Serilog.ILogger Log => Serilog.Log.ForContext(typeof(PolicyRegistryExtensions));
[DebuggerStepThrough]
public static IAsyncPolicy<T> GetAsyncPolicy<T>(this IReadOnlyPolicyRegistry<string> policyRegistry, string policyName,
[CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0)
{
if (policyRegistry == null) throw new ArgumentNullException(nameof(policyRegistry));
if (policyName == null) throw new ArgumentNullException(nameof(policyName));
var policy = policyRegistry.Get<IAsyncPolicy<T>>(policyName);
if (policy != null) return policy;
// ReSharper disable ExplicitCallerInfoArgument
Log.Here(memberName, sourceFilePath, sourceLineNumber)
.Warning("No policy was registered with name {name}. Using Fallback.", policyName);
// ReSharper restore ExplicitCallerInfoArgument
return Policy.NoOpAsync<T>();
}
}
}
namespace MyApp
{
public sealed class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
}
public IConfiguration Configuration { get; }
// ReSharper disable once UnusedMember.Global
public void ConfigureServices(IServiceCollection services)
{
services.AddPolicies();
// TODO: register additional services
}
// ReSharper disable once UnusedMember.Global
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// TODO: setup application
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment