Я пытаюсь внедрить систему поиска событий, используя методы и принципы в соответствии с различными примерами, вдохновленными Грегом Янгом, которые я видел.
Я понимаю, как работает логика проверки версии, и что при сохранении агрегата, если текущая версия не соответствует ожидаемой версии, это означает, что другое сеансовое/клиентское приложение обновило агрегат раньше вас.
Я также понимаю, что у вас может быть метод ретроспективного разрешения конфликтов, когда параллельные события были сохранены, этот вопрос не столько об этом.
Я пытаюсь понять, что в конкретной реализации с использованием базы данных 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 был бы отличным, так как это то, с чем я планирую создать прототип своей системы поиска событий.