原文:https://www.cnblogs.com/savorboard/p/cap-6-2.html
作者:楊曉東
前言
今天,我們很高興宣布 CAP 發布 6.2 版本正式版,在這個版本中我們主要做了一些功能優化,以及針對目前已經發現的幾個 BUG 進行了修復了。
那么,接下來我們具體看一下吧。
總覽
可能有些人還不知道 CAP 是什么,老規矩來一個簡介。
CAP 是一個用來解決微服務或者分布式系統中分布式事務問題的一個開源項目解決方案(https://github.com/dotnetcore/CAP)同樣可以用來作為 EventBus 使用,該項目誕生于2016年,目前在 Github 已經有超過 5500+ Star 和 70+ 貢獻者,以及在 NuGet超 250 萬的下載量,并在越來越多公司的和項目中得到應用。
如果你想對 CAP 更多了解,請查看我們的 官方文檔。
本次在 CAP 6.2 版本中我們主要帶來了以下新特性:
Dashboard 添加中文支持
事務對象更友好的對接第三方ORM
消費執行消息頭記錄 InstanceId
啟動時對位于相同組的訂閱者進行警告
BUG 修復
Snowflake Id 算法生成時排除虛擬,回環和禁用的網卡
修復 RabbitMQ 丟失連接并快速恢復時的健康檢測Bug。
修復 Dashboard 代理查詢缺失 QueryString 的問題。
修復 MongoDB 查詢元素未注冊不返回結果的Bug。
修復 Scoped 生命周期工廠模式注冊的訂閱者報錯的Bug。
Dashboard 添加中文支持
我們在 5.1.1 版本中使用 Vue 重構了我們的 Dashboard,由于時間原因,我們的新版本的 Dashboard 只對英文提供了支持。
在該版本中我們重新提供了對中文的支持,目前可自動根據你的瀏覽器檢測使用的語言并展示。
你也可以在右上方進行手動切換。

感謝 @tetris1128 對此提交的PR!
事務對接第三方 ORM 更加友好
在 CAP 中,事務對象需要交給 CAP 進行提交從而在事務實現提交后對緩存消息到 Broker 的 Flush 動作,而目前的Orm大部分都有自己的事務管理對象進行事務的提交。CAP官方直接原生支持使用 ADO.NET 和 EntityFrameworkCore 進行事務集成,而對于第三方ORM則需要自行擴展。
在本版本中,我們做了一個小調整(將 CapTransactionBase 中的 DbTransaction 設置為了 Virtual),沒想到這個小調整讓我們對第三方ORM的兼容性得到了大大增強,現在第三方ORM可以更加友好的對接CAP。
以下是2個第三方ORM的集成示例:
FreeSql Repository+UnitOfWork 事務模式 和 CAP 的 集成
Chloe Orm 和 CAP 的集成
示例:與 FreeSql 集成
FreeSql Repository+UnitOfWork 事務模式 和 CAP 的 集成示例如下:
public?class?FreeSqlRepositoryPatternTransaction?:?CapTransactionBase
{public?FreeSqlRepositoryPatternTransaction(IDispatcher?dispatcher,?IUnitOfWork?uow)?:?base(dispatcher){Uow?=?uow;}public?IUnitOfWork?Uow?{?get;?}public?override?object??DbTransaction?=>?Uow.GetOrBeginTransaction();public?override?void?Commit(){Uow.Commit();Flush();}public?override?Task?CommitAsync(CancellationToken?cancellationToken?=?default){throw?new?NotImplementedException();}public?override?void?Rollback(){Uow.Rollback();}public?override?Task?RollbackAsync(CancellationToken?cancellationToken?=?default){throw?new?NotImplementedException();}public?override?void?Dispose(){Uow.Dispose();}
}public?static?class?Extensions
{//?注意:你可以酌情修改此擴展以支持你的使用習慣public?static?ICapTransaction?BeginTransaction(this?IFreeSql?freeSql,ICapPublisher?publisher,?out?IRepositoryUnitOfWork?uow,?bool?autoCommit?=?false){var?dispatcher?=?publisher.ServiceProvider.GetRequiredService<IDispatcher>();uow?=?freeSql.CreateUnitOfWork();var?transaction?=?new?FreeSqlRepositoryPatternTransaction(dispatcher,?uow){AutoCommit?=?autoCommit};return?publisher.Transaction.Value?=?transaction;}
}
使用發送帶有事務的消息。
[Route("~/with/test")]
public?IActionResult?WithTransaction()
{using?(var?transaction?=?_freeSql.BeginTransaction(_capBus,?out?var?uow,?false)){_capBus.Publish("sample.rabbitmq.mysql",?DateTime.Now);var?person?=?_freeSql.GetRepository<Person2>();person.UnitOfWork?=?uow;person.Insert(new?Person2()?{?Name?=?"HelloWorld2"?});transaction.Commit();}return?Ok();
}
你可以在這里查看到 FreeSql DbContext 事務模式的對接方式。
示例:與 Chloe 集成
Chloe Orm 和 CAP 進行集成如下:
public?class?ChloeTransaction?:?CapTransactionBase
{public?ChloeTransaction(IDispatcher?dispatcher,?IDbSession?session)?:?base(dispatcher){DbSession?=?session;??????}public?IDbSession?DbSession?{?get;?set;?}public?override?object??DbTransaction?=>?DbSession.CurrentTransaction;public?override?void?Commit(){DbSession.CommitTransaction();Flush();}public?override?Task?CommitAsync(CancellationToken?cancellationToken?=?default){throw?new?NotImplementedException();}public?override?void?Rollback(){DbSession.RollbackTransaction();}public?override?Task?RollbackAsync(CancellationToken?cancellationToken?=?default){throw?new?NotImplementedException();}public?override?void?Dispose(){(DbTransaction?as?IDisposable)?.Dispose();}
}public?static?class?Extensions
{public?static?ICapTransaction?BeginTransaction(this?IDbContext?dbContext,ICapPublisher?publisher,?bool?autoCommit?=?false){?var?dispatcher?=?publisher.ServiceProvider.GetRequiredService<IDispatcher>();dbContext.Session.BeginTransaction();var?transaction?=??new?ChloeTransaction(dispatcher,dbContext.Session){AutoCommit?=?autoCommit};return?publisher.Transaction.Value?=?transaction;}
}
發送帶有事務的消息:
[Route("~/with/test")]
public?IActionResult?WithTransaction()
{using?(_dbContext.BeginTransaction(_capBus,?true)){_dbContext.Insert(new?Person2()?{?Name?=?"HelloWorld"?});???????????_capBus.Publish("sample.rabbitmq.mysql",?DateTime.Now);}return?Ok();
}
相關鏈接:https://github.com/shuxinqin/Chloe/issues/328
消費執行消息頭記錄 InstanceId
某天的一個下午,我的同事告訴我他在使用CAP進行本地的消息調試的時候,消息已經被消費執行了,而且狀態也變成成功了,但是沒進他的VS斷點,他又說有時候又會進斷點,他不知道怎么回事,于是就把我叫過去了。
我過去看了一下,發現開發服務器上也部署的有應用,并且使用的同一個RabbitMQ,他的消息被線上部署的其他實例給消費掉了,所以沒進斷點。之所以有時候又進斷點則是因為消息是負載消費的,恰好又輪到了他本地。
基于以上原因,在這個版本中,我們在消費的消息頭中記錄了執行所在的 InstanceId,也就是機器的 Hostname,這樣在查看消息就很方便的知道消息是被哪個實例給消費掉了,便于排查問題。
啟動時對位于相同組的訂閱者進行警告
某天的一個下午,我的同事又找到了我,說他在使用CAP進行消費的時候,調試的VS斷點一直不進和上次不一樣的是這次始終進不了,但是消息又消費成功了,他找了半天也不知道怎么回事,于是就把我又叫過去了。
我過去看了一下,他沒有犯和上次一樣的錯誤。于是我檢查了一下,發現他在一個服務中弄了2個名稱一樣的訂閱者,并且使用的默認組。由于2個訂閱者位于不同的類中,所以他沒有發現。熟悉CAP的都知道,CAP 在啟動的時候由于進行了去重處理,所以只會使用其中的一個訂閱者,對于另外一個會忽略掉。
基于以上原因,在這個版本中,我們在啟動的時候進行了檢測,如果發現在一個組中有2個以上的同名訂閱者,我們會進行警告日志的打印進行提醒,但不會拋出異常來阻止你的啟動。
BUG 修復
在這個版本中,我們進行了一些已發現的BUG修復,下面是修復的內容項。
Snowflake Id 算法生成時排除虛擬,回環和禁用的網卡
修復 RabbitMQ 丟失連接并快速恢復時的健康檢測Bug。
修復 Dashboard 代理查詢缺失 QueryString 的問題。
修復 MongoDB 查詢元素未注冊不返回結果的Bug。
修復 Scoped 生命周期工廠模式注冊的訂閱者報錯的Bug。
總結
以上,就是本版本我們做出的一些支持和改動,感謝大家的支持,我們很開心能夠幫助到大家 。大家在使用的過程中遇到問題希望也能夠積極的反饋,幫助CAP變得越來越好。