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的文章,但它并不处理您确切的情况,但可能会给您一些关于并发冲突解决方案的想法。