Межагрегатное общение
В настоящее время у меня есть один поток событий на один агрегатный корень и два агрегатных корня, Room
а также RoomType
,
Поведение Room
зависит от того RoomType
это. Чтобы отделить оба агрегата, RoomType
просто представлен как roomTypeId в Room
агрегат. Изменение RoomType
представлен RoomTypeChanged
событие.
RoomTypes
могут управляться отдельно и должны быть в другом агрегате.
Теперь рассмотрим следующий вариант использования:
Когда пользователь делает недействительным RoomType
, все Rooms
которые имеют это Roomtype
следует переключиться на запасной вариант RoomType
,
Я подумал о нескольких подходах, но все они кажутся проблематичными:
Попросите слушателя события прослушать
RoomTypeInvalidated
и отправьтеSwitchToFallbackRoomType
на всеRoom
-агрегаты, которые имеют этоRoomtype
, Как бы я это сделал? Там нет никакого способа узнать, какие агрегаты имеют этоRoomtype
если я не получаю доступ к моей модели чтения, которая кажется неправильной. Даже если бы я должен был загрузить все агрегаты, нет способа загрузить только агрегаты этого типа, так как я не могу загрузить подмножество всех потоков (используя geteventstore).При повторном применении
RoomTypeChanged
события кRoom
агрегат, вместо того, чтобы просто применить его, сделайте проверку, чтобы увидеть, является ли этоRoomType
все еще существует, но опять же, как бы я узнал, какиеRoomTypes
существует (я был бы в той же ситуации, что и 1, но перевернут)? Кроме того, кажется неправильным вводить логику в повторное применение событий, они должны просто представлять изменения состояния, я думаю.
Как бы вы решили это?
3 ответа
Мы работаем с той же проблемой, а также номера и типы номеров. Решение, к которому у вас возникли проблемы, вероятно, сопоставлено с реляционным, где это не проблема. Трудно и запутанно думать о том, чтобы начать думать о поведении в области, которая в значительной степени зависит от данных. Я думаю, что для решения проблемы вам необходимо оспорить предложенное решение.
Когда мы переосмыслили это, мы получили агрегаты, такие как RoomAssignment и RoomAllocationSchedule, и обнаружили, что RoomType в основном используется для передачи функций комнаты внешним каналам / OTA.
Моделирование поведения, в котором мы нуждаемся, действительно помогает (поскольку границы согласованности начинают обретать смысл) вместо того, чтобы моделировать данные и пытаться навязать им реляционное согласованное поведение...
Когда нам действительно нужна согласованность по агрегатам, мы моделируем диспетчер процессов / сагу, которая сама по себе является транзакционно согласованной, и отправляем агрегатам сообщения. Таким образом, у нас есть агрегат RoomAssignmentDirector, который гарантирует, что комната выделена для проживания в номере, прежде чем она будет назначена для пребывания в номере и т. Д.
Надеюсь, поможет.
Решение этой проблемы путем обеспечения полной согласованности данных каждый раз, когда работает против проекта. Event Sourcing предполагает, что система в конечном итоге будет согласованной, поэтому наличие несоответствий в модели чтения является нормальным и ожидаемым.
Лучший способ решить эту проблему - запросить модель чтения для всех комнат с новым недействительным TypeId (ваше решение 1). После обновления всех этих комнат существует вероятность того, что есть несколько отставших, которые не были обновлены, поэтому вы перезапустите обработчик событий несколько минут спустя (скажем, минуту).
В этот момент (при условии, что ваши Команды проверяют правильность типа комнаты при создании комнаты), невозможно создать новые комнаты со старым типом комнаты, и модель чтения для отставших должна уже стабилизироваться. Поэтому повторный запуск кода обновит все остальное.
Почему бы не использовать менеджер процессов для каждого типа комнаты и иметь список комнат как свойство менеджера процесса?
Запрос модели чтения из службы или из обработчика команд не гарантирует согласованную структуру. Что если комнате был присвоен недействительный тип комнаты, но модель чтения еще не была обновлена? (это своего рода сценарий, с которым я сталкиваюсь)