Проблема NEventStore с воспроизведением событий

Мы используем CQRS + ES. ES - это NEventStore (далее JOliver EventStore). У нас есть 2 агрегата в разных командах. Проекции второго AR зависят от данных, записанных первыми проекциями AR в модели чтения. Проблема в том, что когда мы запускаем программное обеспечение, все происходит так быстро, что иногда два агрегата сохраняются в хранилище событий с одинаковыми датами времени (столбец CommitStamp). При воспроизведении событий мы получаем их с самого начала в порядке столбца CommitStamp. Но если эти два потока имеют идентичный CommitStamp и взяты в неправильном порядке, проекции модели чтения срываются с исключениями.

Есть идеи, как решить эту проблему?

===============================

Вот обсуждение этой проблемы на github https://github.com/NEventStore/NEventStore/issues/170

===============================

РЕДАКТИРОВАТЬ: именно так мы сейчас воспроизводим события. Я искал, как работает GetFrom (...), и оказалось, что столбец commitstamp не используется для упорядочивания. Ведь не существует порядка совершения. Итак, если я начну воспроизводить события, он может вернуть событие с сегодняшнего дня, следующее событие, записанное 2 года назад, следующее и т. Д.

public void ReplayEvents(Action<List<UncommittedEvent>> whatToDoWithEvents, DateTime loadEventsAfterDate)
    {
        var eventPortion = store.Advanced.GetFrom(loadEventsAfterDate);

        var uncommitedEventStream = new UncommittedEventStream();
        foreach (var commit in eventPortion)
        {
            foreach (var eventMessage in commit.Events.ToList()))
            {
                uncommitedEventStream.Append(new UncommittedEvent(eventMessage.Body));
            }
        }
        whatToDoWithEvents(uncommitedEventStream.ToList());
    }

person mynkow    schedule 05.07.2013    source источник
comment
Это известная проблема (№ 159); по крайней мере, для некоторых бэкэндов с постоянством. Какой движок постоянства вы используете?   -  person Marijn    schedule 06.07.2013
comment
Мы используем MSSQL 2008   -  person mynkow    schedule 08.07.2013
comment
@Marijn: Это как раз наша проблема.   -  person mynkow    schedule 08.07.2013


Ответы (3)


В NEventStore границей согласованности является поток. Начиная с версии 3.2 (как упоминалось в @Marijn, проблема № 159) используется столбец CommitSequence для упорядочивания сообщений CommitMessages (и содержащихся в них сообщений EventMessages) при чтении из потока через все механизмы сохранения.

Порядок сообщений EventMessage гарантируется для каждого потока. Не существует подразумеваемого упорядочивания сообщений по потокам. Любое фактическое упорядочение, которое может произойти в результате того или иного аспекта выбранного механизма постоянства, является случайным, и на него нельзя полагаться.

Гарантированное упорядочение потоков сильно ограничит аспекты библиотеки, ориентированные на распределение. Даже если бы мы рассмотрели такую ​​возможность, она должна была бы работать со всеми поддерживаемыми механизмами сохранения состояния, включая хранилища NoSQL.

Если вы практикуете проектирование, управляемое доменом, где каждый поток представляет собой совокупный корень, и вам необходимо гарантировать упорядочение по 2 или более агрегатам, это указывает на проблему проектирования в вашей модели предметной области.

Если в ваших прогнозах необходимо объединить значения из нескольких источников (потоков), вы можете положиться на упорядочение внутри источника, но вам нужно быть гибким при упорядочивании между источниками. Вы также должны учитывать возможность дублирования сообщений, особенно если вы воспроизводите их через внешнюю шину или очередь.

Если вы попытаетесь переупорядочить несколько потоков на стороне получателя, используя временную метку (CommitStamp), это будет хрупким. Метки времени имеют фиксированное разрешение (мс, тик и т. Д.). Даже с одним писателем все может происходить «одновременно».

person Community    schedule 08.07.2013
comment
Хорошо, но вы что-то здесь упускаете. Представьте, что домен спроектирован таким образом, чтобы он работал правильно. Ссылки между AR только по идентификатору. Но при воспроизведении потоков магазин может сначала вернуть поток, созданный сегодня, а следующий может быть потоком, созданным 5 месяцев назад. Я не думаю, что это в любом случае правильно. - person mynkow; 08.07.2013
comment
@mynkow В книге IDDD рекомендуется хранить только идентификаторы упомянутых AR. Если вам нужно написать код, охватывающий несколько агрегатов, используйте сагу с конечным автоматом, который может ждать, пока не появятся все необходимые события. Тогда порядок создания нескольких агрегатов не имеет значения. - person Alexander Langer; 20.11.2013
comment
Это ненужная сложность для приложения, чтобы исправить ошибку фреймворка. И этот баг уже решен. Ознакомьтесь с последними коммитами Дамиана. - person mynkow; 20.11.2013

Дамиан добавил в базу данных столбец с контрольными точками. Это в текущей основной ветке. Когда события a воспроизводятся с GetFromCheckpoint(int), результаты верны.

person mynkow    schedule 13.11.2013

На уровне базы данных, хотя CommitStamp подходит для фильтрации, столбец CommitSequence - это столбец, который должен определять порядок.

Что касается того, что это переводится с точки зрения вызовов API для любой версии библиотек, которые вы используете - я оставлю это в качестве упражнения для вас (или если вы заполните фрагмент кода и / или упомянете версию возможно, кто-то другой может вмешаться)

person Ruben Bartelink    schedule 05.07.2013
comment
Я добавил метод, который мы экспериментируем для воспроизведения событий - person mynkow; 05.07.2013