私が見たグレッグ・ヤングにインスパイアされたさまざまな例に沿った実践と原則を使用して、イベントソーシングシステムを実装しようとしています。
バージョン チェック ロジックのしくみと、集計を保存するときに、現在のバージョンが予想されるバージョンと一致しない場合は、別のセッション/クライアント アプリが集計を更新する前に更新したことを意味することを理解しています。
また、同時イベントが保存されたときに競合をさかのぼって解決する方法を用意できることも理解しています。この質問は、これを行うことではありません。
私が理解しようとしているのは、ravendb などの nosql データベースをイベント ストアとして使用する特定の実装では、競合状態のために書き込まれたイベントがバージョン番号と重複しないようにするにはどうすればよいかということです。
サンプル プロジェクトからの次のコードを示します。
Repository<TAggregate>
リポジトリ クラスには save メソッドがあります
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);
}
}
}
基本的に、アプリケーションが 1 つしかない場合、これは問題なく機能します。ロックは、現在のスレッドがロックを取得し、バージョンをチェックしてから、独自のイベントを書き込んでいる間、他のスレッドがイベント ストアにイベントを書き込んでいるのを停止します。
ただし、異なるマシンで実行されている 2 つの別個のクライアントを想像してみてください。明らかに、2 つのプロセスは両方とも一緒にロックされ、GetById()
メソッドを実行して、現在コミットされている同じバージョンを確認できます。両方のプロセスは、バージョン番号をインクリメントして、コミットされていないイベントを書き込みます。ただし、これにより、アグリゲートのイベント ストリームは、同じバージョン番号の異なるイベントが存在する可能性がある状態のままになります。
ある種のレトロスペクティブな解決策を実行できることは知っていますが、それは私が達成しようとしていることではありません。
これは明らかに、イベント ストア データベース側で何らかのロックを行う必要があることを意味します。誰でもこれを行う方法をアドバイスできますか? 回答はデータベース固有である必要はありませんが、イベント ソーシング システムのプロトタイプを作成しようと計画しているため、ravendb の例は素晴らしいでしょう。