.net core 3.1 基于AspectCore+Polly 实现熔断降级

这次学习主要参考了Edison zhou 的这篇文章:https://www.cnblogs.com/edisonchou/p/9159644.html,相关的概念也做了解释,有兴趣的可以了解一下 

本次实现需要引用以下包,版本也有要求(包括Autofac),稍后会进行解释。 我先把实现逻辑讲完,再分享其中遇到的坑

如果对AspectCore不太了解的,可以下载查看AspectCoreDemo ,了解AspectCore拦截器设置。

使用AspectCore前,把原来的Castle相关引用删除,避免冲突,同时前文提到的 LogInterceptor , MyInterceptor 先注释相关代码,后续会使用 AspectCore 实现基于方法的拦截

首先新建自定义拦截类CustomInterceptorAttribute ,这里要using AspectCore.DynamicProxy;

/// <summary>
/// 自定义拦截器
/// </summary>
public class CustomInterceptorAttribute : AbstractInterceptorAttribute
{
/// <summary>
/// 每个被拦截的方法中执行
/// </summary>
/// <param name="context"></param>
/// <param name="next"></param>
/// <returns></returns>
public override async Task Invoke(AspectContext context, AspectDelegate next)
{
try
{
Console.WriteLine("Before service call");
await next(context); // 执行被拦截的方法
}
catch (Exception)
{
Console.WriteLine("Service threw an exception");
throw;
}
finally
{
Console.WriteLine("After service call");
}
}
}

依赖注入是借助Autofac ,在Program.cs 增加如下代码 .UseServiceProviderFactory(new AutofacServiceProviderFactory())

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory()) //autofac 依赖注入
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});

在Startup.cs 的ConfigureContainer 方法最后加入一行代码 添加引用 AspectCore.Extensions.Autofac

builder.RegisterDynamicProxy();

AspectCore 配置完成了,接下来是 Polly+AspectCore 结合使用

这里引用杨中科老师封装的 RuPeng.HystrixCore ,里面定义好了相关Polly配置和执行逻辑,后续只要添加相关属性值就可以实现动态配置。

同步引用 AspectCore.Core, Microsoft.Extensions.Caching.Memory(对熔断后操作数据做缓存)

接下来是调用方法。

新建IProductService.cs

在相关的接口添加Polly属性配置,具体的属性含义可以查看 RuPeng.HystrixCore 源代码,GetAllProductsFallBackAsync 是Fallback接口

public interface IProductService
{
[HystrixCommand(nameof(GetAllProductsFallBackAsync),
EnableCircuitBreaker = true, CacheTTLMilliseconds =1000*6,
ExceptionsAllowedBeforeBreaking = 2,
MillisecondsOfBreak = 1000 * 6)]
string GetAllProductsAsync(string productType);

string GetAllProductsFallBackAsync(string productType);
}

ProductService.cs

public class ProductService : IProductService
{
public string GetAllProductsAsync(string productType)
{
NLogHelper.logger.Info("test for GetAllProductsAsync:" + productType);
string str = null;
str.ToString();

// to do : using HttpClient to call outer service to get product list
return $"OK {productType}";
}

public string GetAllProductsFallBackAsync(string productType)
{
NLogHelper.logger.Info("test for GetAllProductsFallBackAsync:"+productType);
return $"OK for FallBack {productType}";
}
}

新建ProductController.cs

[Route("api/[controller]/[action]")]
[ApiController]
public class ProductController : ControllerBase
{
private readonly IProductService _baseService;
public ProductController(IProductService baseService)
{
_baseService = baseService;
}

[HttpGet]
public async Task<string> Get(string productType="A")
{
var product = _baseService.GetAllProductsAsync(productType);
return product;
}
}

注意,Get方法用异步线程

最后调试:

调试完,接着说说版本号的问题以及遇到的坑

最初引用 AspectCore.Extensions.Autofac 注入匿名代理时,无法编译通过,提示Method not found: 'Autofac.Builder.DeferredCallback Autofac.ContainerBuilder.RegisterCallback(System.Action`1<Autofac.Core.IComponentRegistry>)'.

后来 在AspectCore-Framwork 项目提交issues ,解释说已处理但没发布,暂时可以先降级Autofac到4.9 版本,于是把相关的引用降级,编译通过

在引用 RuPeng.HystrixCore 调试时有个bug,fallback接口没有把参数传过来,导致每次传不同参数调用接口都是返回之前的参数值,后来下载源码修改

Object fallBackResult = fallBackMethod.Invoke(context.Implementation, context.Parameters); 

改为

Object fallBackResult = fallBackMethod.Invoke(context.Implementation, aspectContext.Parameters); 

编译后替换,问题解决

此外RuPeng.HystrixCore 不兼容Polly 7 ,所以要把Polly 版本降为6.0.1

原文地址:https://www.cnblogs.com/redo/p/12575592.html