Как справиться с проверкой согласованности на основе набора в CQRS?
У меня есть довольно простая модель предметной области, включающая список Facility
совокупные корни. Учитывая, что я использую CQRS и шину событий для обработки событий, возникающих в домене, как вы можете обрабатывать проверку на наборах? Например, скажем, у меня есть следующее требование:
Facility
должно иметь уникальное имя.
Поскольку я использую в конечном итоге согласованную базу данных на стороне запроса, данные в ней не гарантируются точными в то время, когда обработчик событий обрабатывает событие.
Например, FacilityCreatedEvent
находится в очереди обработки событий базы данных запросов и ожидает обработки и записи в базу данных. Новый CreateFacilityCommand
отправляется в домен для обработки. Доменные службы запрашивают базу данных на чтение, чтобы узнать, есть ли другие Facility
зарегистрировано уже с таким именем, но возвращает false, потому что CreateNewFacilityEvent
еще не был обработан и записан в магазин. Новый CreateFacilityCommand
Теперь удастся и вырвет другой FacilityCreatedEvent
который взорвется, когда обработчик событий попытается записать его в базу данных и обнаружит, что другой Facility
уже существует с этим именем.
4 ответа
Решение, с которым я пошел, состояло в том, чтобы добавить System
совокупный корень, который может поддерживать список текущих Facility
имена. При создании нового Facility
Я использую System
совокупный (только один System
как глобальный объект / синглтон) как фабрика для него. Если данное имя объекта уже существует, оно выдаст ошибку проверки.
Это сохраняет ограничения проверки в домене и не полагается на в конечном итоге непротиворечивое хранилище запросов.
В возможной последовательности и проверке набора изложены три подхода:
- Если проблема редкая или не важная, решите ее в административном порядке, возможно, отправив уведомление администратору.
- Отправьте событие DuplicateFacilityNameDetected, которое может запустить автоматический процесс разрешения.
- Поддерживать Службу, которая знает об используемых именах Объекта, возможно, путем прослушивания событий домена и ведения постоянного списка имен. Перед созданием любого нового объекта, проверьте с этим сервисом.
Также см. Этот связанный вопрос: проверка уникальности при использовании CQRS и источников событий
В этом случае вы можете реализовать простой сервис в стиле CRUD, который в основном выполняет вставку в таблицу Sql с ограничением первичного ключа.
Вставка произойдет только один раз. Когда дубликаты команд с одним и тем же значением, которое должно существовать только один раз, попадают в агрегат, агрегат вызывает службу, служба завершает сбоем операцию вставки из-за нарушения ограничения первичного ключа, выдает ошибку, весь процесс завершается неудачно и событий нет генерируется, нет отчетов на стороне запроса, может быть отчет о сбое в таблице для возможной проверки согласованности, где пользователь может запросить, чтобы узнать статус обработки команды. Чтобы проверить это, просто запросите снова и снова модель представления статуса команды с помощью Command Guid.
Очевидно, что когда команда содержит значение, которое не существует в таблице для проверки первичного ключа, операция завершается успешно.
Таблицу ограничения первичного ключа следует использовать только как службу, но, поскольку вы реализовали источник событий, вы можете воспроизвести события, чтобы перестроить таблицу ограничения первичного ключа.
Поскольку проверка уникальности выполняется перед записью данных, лучший способ состоит в создании службы отслеживания событий, которая отправляла бы уведомление о завершении или завершении процесса.