CAP 6.2 版本釋出通告

2022-09-19 18:02:07

前言

今天,我們很高興宣佈 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 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 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變得越來越好。