4

我試圖實現使用的做法和原則符合各種Greg Young的啓發我見過的例子事件採購系統事件存儲。實現與併發檢查了多個客戶端

我理解的版本檢查邏輯是如何工作的,並且保存彙總時,如果當前的版本不符合預期的版本就意味着另一個會話/客戶端應用程序更新了總你以前。

我也明白,你可以在地方有追溯解決衝突的方法,當併發事件已經保存,這個問題是沒有這麼多事情了。

我想了解的是,在使用nosql數據庫(如ravendb作爲事件存儲)的特定實現中,如何確保由於競爭條件而寫入的事件從不重疊版本號。

從實例項目下面的代碼來說明:

Repository<TAggregate>倉儲類有一個保存方法

public void Save(AggregateRoot aggregate, int expectedVersion) 
    { 
     if (aggregate.GetUncommittedChanges().Any()) 
     { 
      lock (_lockStorage) 
      { 
       var item = new T(); 

       if (expectedVersion != -1) 
       { 
//issue if two processes get to this line of code below together 
//and both have the same 'version to be expected' then start writing together 
        item = GetById(aggregate.Id); 
        if (item.Version != expectedVersion) 
        { 
         throw new ConcurrencyException(string.Format("Aggregate {0} has been previously modified", 
                    item.Id)); 
        } 
       } 

       _storage.Save(aggregate); 
      } 
     } 
    } 

現在基本上是當只有一個單一的應用程序能正常工作。在當前線程取得鎖定,鎖定版本,然後編寫自己的事件時,鎖定將停止任何其他線程將事件寫入事件存儲。

然而,想象兩個獨立的客戶端運行在不同的機器上。很明顯,這兩個進程都可以同時進入鎖,它們都可以執行GetById()方法,並且都看到相同的當前提交版本。這兩個進程將繼續用增加的版本號編寫未提交的事件。但是,這會將聚合的事件流留在可能有不同事件具有相同版本號的狀態。

我知道我可以做一些回顧性的分辨率,但是這不是我想要完成的任務。

現在,很顯然,這意味着需要對事物的事件存儲數據庫端完成某種鎖定。任何人都可以建議如何做到這一點?答案並不一定是數據庫特定的,但ravendb的例子會很好,因爲這正是我打算用我的事件採購系統的原型。

回答

1

沒有任何理由在不同的機器上運行兩個獨立的客戶端無法通過API的應用程序進行交互?這樣,事件的中央處理就可以在一臺機器上處理,並避免您描述的問題。如果您指的是部分連接的場景,那麼您仍然不會在客戶端上執行此邏輯。如果這是不可避免的,則需要在某個時間點合併事件流,然後處理衝突。

如果有幫助,我確實有一篇關於處理concurrency issues的文章,但它並不處理您確切的情況,但可能會給您一些關於併發衝突解決方案的想法。