Если вы проверяете имя пользователя, используя модель чтения, перед отправкой команды, мы говорим об окне условий гонки в пару сотен миллисекунд, где может возникнуть реальное состояние гонки, которое в моей системе не обрабатывается.Слишком маловероятно, что это произойдет по сравнению с затратами на его решение.
Однако, если вы чувствуете, что по какой-то причине вам необходимо с этим справиться, или если вы просто хотите знать, как справиться с таким делом,Вот один из способов:
При использовании источников событий не следует обращаться к модели чтения из обработчика команд или из домена.Однако вы можете использовать доменную службу, которая будет прослушивать событие UserRegistered, в котором вы снова получаете доступ к модели чтения и проверяете, не является ли имя пользователя по-прежнему дубликатом.Конечно, вам нужно использовать UserGuid здесь, так как ваша модель чтения могла быть обновлена пользователем, которого вы только что создали.Если найден дубликат, у вас есть возможность отправить компенсирующие команды, такие как изменение имени пользователя и уведомление пользователя о том, что имя пользователя было взято.
Это один из подходов к проблеме.
Как вы, вероятно, можете видеть, это невозможно сделать синхронным способом запрос-ответ.Чтобы решить эту проблему, мы используем SignalR для обновления пользовательского интерфейса всякий раз, когда мы хотим что-то передать клиенту (если они все еще подключены, то есть).Что мы делаем, так это позволяем веб-клиенту подписываться на события, содержащие информацию, полезную для немедленного просмотра клиентом.
Обновление
Для более сложного случая:
Я бы сказал, что размещение заказа менее сложное, поскольку вы можете использовать модель чтения, чтобы выяснить, является ли клиент ценным, прежде чем отправлять команду.На самом деле, вы можете запросить это при загрузке формы заказа, так как вы, вероятно, хотите показать клиенту, что он получит скидку 10%, прежде чем он разместит заказ.Просто добавьте скидку к PlaceOrderCommand
и, возможно, причину скидки, чтобы вы могли отслеживать, почему вы сокращаете прибыль.
Но опять же, если вам действительно нужно рассчитать скидку после того, как заказ былместами по какой-то причине снова используйте доменную службу, которая будет прослушивать OrderPlacedEvent
, а «компенсирующая» команда в этом случае, вероятно, будет DiscountOrderCommand
или что-то в этом роде.Эта команда повлияет на корень Order Aggregate, и информация может быть передана вашим моделям чтения.
Для случая с повторяющимся именем пользователя:
Youможет отправить ChangeUsernameCommand
в качестве компенсирующей команды от службы домена.Или даже что-то более конкретное, описывающее причину, по которой изменилось имя пользователя, что также может привести к созданию события, на которое веб-клиент может подписаться, чтобы вы могли позволить пользователю увидеть, что имя пользователя является дубликатом.
В контексте службы домена я бы сказал, что у вас также есть возможность использовать другие средства для уведомления пользователя, такие как отправка электронного письма, которое может быть полезно, так как вы не можете знать, если пользователь все еще подключен.Возможно, эта функция уведомлений может быть инициирована тем же событием, на которое подписывается веб-клиент.
Когда речь идет о SignalR, я использую концентратор SignalR, к которому подключаются пользователи при загрузке определенной формы.Я использую функциональность SignalR Group, которая позволяет мне создавать группу, которую я называю значением Guid, которое я посылаю в команде.Это может быть userGuid в вашем случае.Затем у меня есть Eventhandler, который подписывается на события, которые могут быть полезны для клиента, и когда событие прибывает, я могу вызвать функцию javascript на всех клиентах в группе SignalR (в этом случае это будет только один клиент, создающий дублирующее имя пользователя в вашемдело).Я знаю, это звучит сложно, но на самом деле это не так.Я все это настроил во второй половине дня.На странице SignalR Github есть отличные документы и примеры.