分布式事务和事务总线 DotNetCoreCap 使用实例
1 创建 CAP.UserService 项目, 安装包 DotNetCore.CAP.SqlServer 和 DotNetCore.CAP.RabbitMQ
在项目 Startup.cs ConfigureServices 方法中调用如下注册方法
#region 使用 DotNetCore.CAP /// <summary> /// 注册 DotNetCore.CAP /// </summary> /// <param name="services"></param> /// <param name="configuration"></param> public static void AddNetCoreCAP(this IServiceCollection services) { services.AddCap(x => { x.UseSqlServer(options => { options.ConnectionString = ConfigurationHelper.GetSection("DatabaseConnectionStrings:SqlServer"); }); x.UseRabbitMQ(options => { options.HostName = ConfigurationHelper.GetSection("RabbitSettings:Host"); options.Port = Convert.ToInt32(ConfigurationHelper.GetSection("RabbitSettings:Port")); options.UserName = ConfigurationHelper.GetSection("RabbitSettings:UserName"); options.Password = ConfigurationHelper.GetSection("RabbitSettings:Password"); }); //失败后的重试次数,默认50次;在FailedRetryInterval默认60秒的情况下,即默认重试50*60秒(50分钟)之后放弃失败重试 x.FailedRetryCount = 10; //失败后的重拾间隔,默认60秒 x.FailedRetryInterval = 60; // 推送到 RabbitMq 失败后的回调 x.FailedThresholdCallback = failed => { }; }); } #endregion
2 启动项目,成功启动后会在数据库创建 cap.Published 和 cap.Received 两张表
3 编写订阅消息的代码
先写订阅代码是为了先绑定队列到交换器,不然如果先定义了交换器,但没有队列,会导致消息丢失
/// <summary> /// 订阅消息 /// </summary> /// <param name="sysUserEntity">发布时传递的参数</param> /// <param name="header">发布时传递header</param> /// <returns></returns> [NonAction] [CapSubscribe("RabbitMQ.SqlServer.UserService", Group = "UserService.Distributed")] // RabbitMQ.SqlServer.UserService 与发布消息设置的 publishName 一致 ; Group 是队列名,会生成 UserService.Distributed.V1 队列)] public IActionResult Consumer(SysUserEntity sysUserEntity, [FromCap] CapHeader header) { return Ok(); }
项目启动成功后会自动创建cap框架默认的交换器 cap.default.router
然后会创建 队列 UserService.Distributed.v1 (队列名规则 Group.v1)
再声明一个订阅者2
[NonAction] [CapSubscribe("RabbitMQ.SqlServer.UserService", Group = "UserService.Aistributed")] // RabbitMQ.SqlServer.UserService 与发布消息设置的 publishName 一致 ; Group 是队列名,会生成 UserService.Aistributed.V1 队列)] public IActionResult Consumer2(SysUserEntity sysUserEntity, [FromCap] CapHeader header) { return Ok(); }
同理会创建队列 UserService.Aistributed.V1
4 编写发布消息的代码
public IActionResult Distributed() { IDictionary<string, string> dicHeaders = new Dictionary<string, string>(); dicHeaders.Add("Day", "20220428"); using (var trans = _userDbContext.Database.BeginTransaction(_capPublisher, autoCommit: false)) { var user = new SysUserEntity { Id = Guid.NewGuid().ToString(), UserCode = "UserCode2", UserName = "UserName2" }; _userDbContext.SysUsers.Add(user); _capPublisher.Publish(PublishName, user, dicHeaders); _userDbContext.SaveChanges(); trans.Commit(); } return Ok(); }
发布成功后,Published 表有一条记录
即使rabbitmq没有启动程序也能正常返回响应因为cap 框架有后台任务来重推信息到mq中。
5 测试
发布新消息前,在 订阅者代码处打上断点,接收到了发布的消息
查询 Received表看到接收到两天记录
参考资源
https://www.bilibili.com/video/BV1b44y1H7yM?p=104&spm_id_from=pageDriver