Как обрабатывать ошибки после проверки в команде (DDD + CQRS)


18

Например, когда вы отправляете форму регистрации, вы должны подтвердить Domain Model( WriteModelв CQRS), что она находится в действительном состоянии (например, синтаксис адреса электронной почты, возраст и т. Д.).

Затем вы создаете Commandи отправляете его Command Bus.

Я понимаю, что Команды не должны ничего возвращать.

Итак, как вы справляетесь с ошибкой Command Bus? (Например, пользователь зарегистрировался за 1 секунду до того же username/email).

Откуда вы знаете, что команда завершилась неудачно, и как вы узнали об ошибке?


2
Вам не нужен автобус для мероприятий. Почему все думают, что вам нужна шина событий при реализации CQRS, я просто не знаю. CQRS просто означает, что вы полностью разделяете записи и чтения, занимаясь отдельными делами. У вас есть CQRS, пока вы делаете это. Ваши команды даже не должны быть асинхронными. Если у вас работают синхронные команды с отчетами об ошибках, сделайте это.
Энди

1
Команды не должны ничего возвращать в случае успеха . Идея началась с CQS , которая подразумевала, что команда все еще может выдать исключение при ошибке. То, что вы описываете, является односторонней командой. Смотрите этот ответ по отношению к этому.
Кейси

Ответы:


4

Я понимаю, что Команды не должны ничего возвращать.

Это одна точка зрения, но она не совсем в камне. Рассмотрим записи (PUT, POST, DELETE) в HTTP - все эти сообщения являются командами в том смысле, что они являются сообщениями с запросом на изменение состояния ресурса, и все же они все возвращают ответы.

Итак, как вы справляетесь с ошибкой за пределами командной шины? (Например, пользователь зарегистрировался за 1 секунду до того же имени / адреса электронной почты).

Откуда вы знаете, что команда завершилась неудачно, и как вы узнали об ошибке?

Таким образом, в случае, когда вы общаетесь напрямую с обработчиком команд, возвращаемое сообщение является вполне разумным способом подтвердить, что команда была получена и обработана.

Если вы используете часть промежуточного программного обеспечения, например, шину, которая не позволяет вам напрямую взаимодействовать с целью, то я бы посоветовал вам обратиться к шаблонам асинхронного обмена сообщениями - как заставить обработчик команд отправлять сообщение обратно вызывающий?

Одна идея состоит в том, чтобы подписаться на результат команды; это заимствовано из некоторых идей в паттернах корпоративной интеграции Hohpe. Основная идея заключается в том, что, поскольку клиент знаком с отправленным командным сообщением, он имеет все возможности для подписки на любые новые сообщения, опубликованные как следствие командного сообщения. Обработчик команд, после сохранения данных в книге записей, публикует события, объявляющие об успешном изменении, и клиент подписывается на эти события - распознавая правильные события, учитывая совпадение различных идентификаторов в сообщении (идентификатор причины, идентификатор корреляции и т. д.).

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

Очень похожая альтернатива - зарезервировать место в командном сообщении для обработчика команды, чтобы написать подтверждение - поскольку клиент уже имеет рассматриваемое командное сообщение, схема уже завершена. Подумайте « обещание » или « выполнимое будущее». Сообщение сообщает обработчику команды, где написать подтверждение; это сигнализирует клиенту (защелка обратного отсчета), что подтверждение доступно.

И, конечно, у вас есть дополнительная опция удаления промежуточного программного обеспечения, которое, кажется, мешает просто делать правильные вещи.

Например, пользователь зарегистрировался за 1 секунду до того же имени пользователя / адреса электронной почты

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


2

Например, когда вы отправляете форму регистрации, вы должны проверить в доменной модели (WriteModel в CQRS), что она находится в действительном состоянии (например, синтаксис адреса электронной почты, возраст и т. Д.)

Существует много видов проверки. Проверка при проверке синтаксиса адреса электронной почты и формата возраста - это тип проверки, который может выполнить команда. Это на самом деле не проблема домена. Может показаться, что это так, потому что некоторые эксперты в области сказали бы вам эти спецификации, но вы должны выполнить такую ​​проверку при создании команды. Фактически, общая идея состоит в том, чтобы выполнить проверку как можно скорее, потому что после того, как команда создана и отправлена ​​в BUS, становится сложнее выполнять действия.

Итак, как вы справляетесь с ошибкой за пределами командной шины? (Например, пользователь зарегистрировался за 1 секунду до того же имени / адреса электронной почты).

Этот вид валидации много обсуждается в сообществе CQRS с самого начала CQRS. Где это сделать? Это очень обсуждается. Я лично использую следующий подход: перед тем, как команда отправляется в BUS, я помечаю имя пользователя / электронную почту как принятые централизованным способом (то есть ограничение уникального индекса для имени пользователя / электронной почты). После этого я отправляю команду. Недостатком является то, что в случае сбоя команды в течение короткого периода времени это имя пользователя берется и не используется; это приемлемо для моего бизнеса, вероятно для вашего бизнеса.

Откуда вы знаете, что команда завершилась неудачно, и как вы узнали об ошибке?

Если асинхронная команда отклонена Агрегатом из-за инварианта домена, необходимо предпринять некоторые меры, выполнив некоторую компенсационную команду, которая каким-то образом уведомляет издателя команды (то есть отправляет объяснительное электронное письмо о том, что команда не выполнена).

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


1

Проверка должна быть выполнена в декораторе. Тогда любая команда, которая нуждается в проверке, может быть оформлена как таковая.

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

Другая возможность - думать о валидации как о типе «запроса», который вернул бы результат валидации. Запустите запрос проверки, а затем, если он пройден, выполните команду. Это было бы альтернативой подходу декоратора.


Мне нравится подход исключения, потому что это самый чистый способ. Но разве исключения не слишком тяжелы для этого?
EresDev

1
HI @EresDev - Да, они тяжелые. Но я не знаю, насколько «достоверны» ваши данные. Допустим, из 1000 записей 2 недействительны. Исключения могут быть жизнеспособными, поскольку они действительно исключительные условия. Теперь рассмотрим 1000 записей с 200 недействительными. В связи с этим следует избегать исключений yes, поскольку 20% ваших данных недействительны. Поэтому я оставляю на ваше усмотрение решать, выбрать этот подход или нет, исходя из вашей текущей достоверности данных. :)
Джон Рейнор

Я добавлю к этому, сказав, что если мы сохраним пример регистрационной формы, где, я думаю, 50% или даже больше пользователей сначала вставят неверные данные, исключение все равно будет в порядке. В бэкэнде веб-приложения вы в основном получаете достоверные данные, потому что веб-интерфейсы также выполняют проверку. Вы получаете, только если что-то пропустило проверку внешнего интерфейса по какому-то редкому случаю или если кто-то дурачится. Таким образом, исключения очень хорошо в этом случае.
EresDev
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.