基于asp.net core 从零搭建自己的业务框架(三)
前言
根据业务处理部分,单体马上就能得知错误与否,快速做出处理,而分布式系统,会因为各种原因,无法如同单体一样立刻处理,所以这个时候需要 处理异常 的,做 补偿、转移、人工干预。
当然也可以直接在消费端做重试/限流和熔断,但是个人理解,不建议,处理失败的转移到低优先顺序的队列,由专门处理失败消费的部分来处理问题,在实际操作中,可以是单独的服务器,不影响业务流程线,处理失败则发送消息,人为干预。
消费/执行错误的处理流程
无论的消费订阅还是Rpc远程调用,一旦处理失败,都应当有 转移错误、补偿以及人工干预 的异常处理
Masstransit默认是有重试的,所以可以根据获取到的重试次数和错误信息,选择是 转移 还是直接 人工干预,补偿则一般应用于支付相关服务,失败则立刻退款/人工处理,这种失败了,重试还是失败
实例编写
基于发布订阅的失败处理
private async Task Execute(ConsumeContext context, ExceptionInfo exceptionInfo)
{
await Console.Out.WriteLineAsync($"Type:{exceptionInfo.ExceptionType} Message:{exceptionInfo.Message}"); if (exceptionInfo.InnerException != null)
{
await Execute(context, exceptionInfo.InnerException);
}
} public async Task Consume(ConsumeContext<Fault<PayOrderEvent>> context)
{
var retryCount = context.GetRetryCount(); if (retryCount == )
{
if (EndpointConvention.TryGetDestinationAddress<PayOrderEvent>(out Uri endPointUrl))
{
await context.Forward(endPointUrl);
}
}
else
{
var exceptions = context.Message.Exceptions; foreach (var exceptionInfo in exceptions)
{
await Execute(context, exceptionInfo);
}
}
}
这是一段很简单的业务逻辑,PayOrderEvent 的消息消费失败后,则会进入这个专门处理 PayOrderEvent 消费失败的方法
当重试处理第三次,获取错误信息,尝试处理错误信息,当重试第五次则转移队列
基于Rpc的消息异常处理
以上这段代码,只适用于发布订阅,Masstransit的Rpc模式则 无法捕获异常,只能在代码段上做try catch处理,或者引入AspectCore做捕获到异常
基于Rpc模式的异常捕获
基于代码而言try catch足以,但是出于项目管理的角度,应该采用AOP(Aspect-Oriented Programming)做代码的职责分离,预留出足够多的通用层,这里AOP部分采用Lemon的作品 AspectCore
AOP特性部分实现如下
public class RpcConsumerAttribute : AbstractInterceptorAttribute
{
public override async Task Invoke(AspectContext context, AspectDelegate next)
{
try
{
await next(context);
}
catch
{
var _arg = context.Parameters[]; if (_arg is ConsumeContext consume)
{
var consumeType = consume.GetType().GetGenericArguments()[];
var property = consume.GetType().GetProperty("Message").GetReflector();
var arg = property.GetValue(consume);
var argType = arg.GetType(); var faultType = typeof(FaultMessage<>).MakeGenericType(argType);
var constructor = faultType.GetConstructor(new[] { argType });
var constructorInfo = constructor.GetReflector();
var instance = constructorInfo.Invoke(arg); var busControl = context.ServiceProvider.GetRequiredService<IBusControl>();
await busControl.Publish(instance);
}
}
}
}
简单的try catch,在异常处理部分使用反射获取出未正常执行的实体,然后发布 FaultMessage<Message> ,其中 Message 是未正常处理的实体类型
其中反射里携带的 GetReflector 取自于Lemon的 AspectCore.Extensions.Reflection ,原理是构建Emit代码,构建委托,然后换成下来,从单纯的反射,变成调用委托执行反射代码,避免的传统的反射调用的嵌套反射执行
public class FaultMessage<TEntity>
where TEntity:class
{
public TEntity Entity { get; } public FaultMessage(TEntity entity)
{
Entity = entity;
}
}
处理业务部分代码如下
[RpcConsumer]
public virtual async Task Consume(ConsumeContext<PayOrderEvent> context)
{
//... 业务代码段不再赘述
} public Task Consume(ConsumeContext<FaultMessage<PayOrderEvent>> context)
{
var message = context.Message;
var sourceMessage = message.Entity; return Task.CompletedTask;
}
调用部分遵循Rpc调用即可
var entity = new PayOrderEvent
{
SourceId = ,
TargetId = ,
Money =
};
var response = await busControl.Request<PayOrderEvent, PayOrderResponse>(entity);
消费 PayOrderEvent 的 部分,只要正常的Ef Core原封不动的写数据即可,执行两次,造成 主键冲突,则被 RpcConsumerAttribute 捕获异常,触发发布到 FaultMessage<PayOrderEvent> 的消费端即可
后话
引入 AspectCore 的这部分,踩了一些雷,感谢社区的 茶姨以及柠檬的帮助 深感个人实力非常薄弱,很多东西未能深入理解,学到用时方恨少
打个小广告
如果有技术交流可以加NCC的群 24791014、436035237,我在群里,有任何关于asp.net core/Masstransit的问题或者建议都可以与我交流,非常欢迎
示例代码:
https://github.com/htrlq/Crud.Sample
基于asp.net core 从零搭建自己的业务框架(三)的更多相关文章
- 基于asp.net core 从零搭建自己的业务框架(二)
前言 对于项目的迭代,如何降低复杂性的要求高于性能以及技术细节的 一个易用的项目,才能迭代到比拼性能,最后拼刺刀的阶段 传统单体项目,都是传统三层,直接请求响应的模式,这类称为Rpc模式,易用性上非常 ...
- 基于asp.net core 从零搭建自己的业务框架(一)
前言 asp.net core版本选择2.2,只是因为个人习惯了vs2017,代码以及设计皆可移植到vs2019,用asp.net core 3.0以及以上运行起来 项目类似选择web api,基础设 ...
- 基于ASP.Net Core开发的一套通用后台框架
基于ASP.Net Core开发一套通用后台框架 写在前面 这是本人在学习的过程中搭建学习的框架,如果对你有所帮助那再好不过.如果您有发现错误,请告知我,我会第一时间修改. 知其然,知其所以然,并非重 ...
- 基于ASP.NET Core 3.0快速搭建Razor Pages Web应用
前言 虽然说学习新的开发框架是一项巨大的投资,但是作为一个开发人员,不断学习新的技术并快速上手是我们应该掌握的技能,甚至是一个.NET Framework开发人员,学习.NET Core 新框架可以更 ...
- 用VSCode开发一个基于asp.net core 2.0/sql server linux(docker)/ng5/bs4的项目(1)
最近使用vscode比较多. 学习了一下如何在mac上使用vscode开发asp.netcore项目. 这里是我写的关于vscode的一篇文章: https://www.cnblogs.com/cgz ...
- 基于ASP.NET Core 6.0的整洁架构
大家好,我是张飞洪,感谢您的阅读,我会不定期和你分享学习心得,希望我的文章能成为你成长路上的垫脚石,让我们一起精进. 本节将介绍基于ASP.NET Core的整洁架构的设计理念,同时基于理论落地的代码 ...
- 如何基于asp.net core的Identity框架在mysql上作身份验证处理
首先了解这个概念,我一开始也是理解和掌握基本的概念,再去做程序的开发.Identity框架是微软自己提供,基于.net core平台,可拓展.轻量 级.面向多个数据库的身份验证框架.IdentityS ...
- 基于Asp.Net Core的简单社区项目源代码开源
2019年3月27号 更新版本 本项目基于 ASP.NET CORE 3.0+EF CORE 3.0开发 使用vs2019 +sqlserver 2017(数据库脚本最低支持sql server 20 ...
- AServer - 基于Asp.net core Kestrel的超迷你http服务器
AServer是基于ASP.NET Core Kestrel封装的一个超迷你http服务器.它可以集成进你的Core程序里,用来快速的响应Http请求,而不需要集成整个ASP.NET Core MVC ...
随机推荐
- java 面向对象(二十):类的结构:代码块
类的成员之四:代码块(初始化块)(重要性较属性.方法.构造器差一些)1.代码块的作用:用来初始化类.对象的信息2.分类:代码块要是使用修饰符,只能使用static分类:静态代码块 vs 非静态代码块3 ...
- SQLAlchemy01 /SQLAlchemy去连接数据库、ORM介绍、将ORM模型映射到数据库中
SQLAlchemy01 /SQLAlchemy去连接数据库.ORM介绍.将ORM模型映射到数据库中 目录 SQLAlchemy01 /SQLAlchemy去连接数据库.ORM介绍.将ORM模型映射到 ...
- Python函数01/函数的初识/函数的定义/函数调用/函数的返回值/函数的参数
Python函数01/函数的初识/函数的定义/函数调用/函数的返回值/函数的参数 内容大纲 1.函数的初识 2.函数的定义 3.函数的调用 4.函数的返回值 5.函数的参数 1.函数初识 # def ...
- bzoj2160拉拉队排练
bzoj2160拉拉队排练 题意: 给一个字符串,求最长的k个回文子串(此处回文子串长度必须为奇数)长度的乘积.字符串长度≤1000000 题解: 先用manacher预处理出第i个字符为中心的最长回 ...
- 日志套餐篇 - log4j2 logback全量套餐
日志套餐篇 - log4j2 logback全量套餐 前情提要: Log4j Log4j2 logback是当下主流的日志框架 slf4j则是新一代的日志框架接口,logback直接实现了slf4j接 ...
- T3 难题 题解
小王在考试中遇到一道难题:方程 a1+a2+„„+an=m 的非负整数解有几个,请你帮他算 一下(这也可以算作他作弊吧). 输入格式 一行,两个以空格隔开的数 n,m,表示方程 a1+a2+„„+an ...
- [转载]Python ImportError: No module named 'requests'解决方法
windows解决办法1.找到easy_install.exe.一般在python的安装路径下的Scripts文件夹中,如C:\Python34\Scripts\easy_install.exe2.从 ...
- 程序员肺被切掉一块还得去加班... 再谈“工作996,生病ICU”
如题,为什么要说再谈“工作996,生病ICU”,因为996问题早已不是一个新问题,在我最近刚出版的新书<SOD框架“企业级”应用数据架构实战>写作期间,爆发了一次程序员“起义”,出现了一个 ...
- Pollard-Rho
\(code:\) ll pri[12]={2,3,5,7,11,13,17,19}; ll mul(ll x,ll y,ll mod) { ll c=(long double)x*y/mod+0.5 ...
- 主机无法访问虚拟机中运行的Django项目
在虚拟机中的linux上运行了Django项目,虚拟机中可以访问,但外部主机无法访问(连接超时),但主机能ping同虚拟机,虚拟机也能ping通主机 需检查三个地方:(后面发现虚拟机的ip地址存在改变 ...