Проверка уникальности при использовании CQRS и источников событий - PullRequest
18 голосов
/ 26 февраля 2012

Я пытаюсь реализовать собственную инфраструктуру CQRS с помощью Event Sourcing, чтобы лучше ее изучить.В качестве примера проекта я использую движок блога, я знаю, что он может быть не совсем подходящим, но я просто хочу поработать над чем-то реальным.

Проблема, с которой я столкнулся сейчас, - это проверка.Каждый пост имеет shortUrl, и shortUrl должен быть уникальным, но где я должен поместить эту проверку в домен?Я знаю, что у меня будет эта проверка, прежде чем я даже отправлю команду, читая из моего хранилища для чтения, чтобы проверить, действительна ли она при создании команды создания сообщения или команды обновления сообщения.

Я могу придумать два "решения".

  1. Имеет совокупность Blog, которая отслеживает все настройки, связанные с блогом, а также ссылки на все сообщения.Но проблема с этим в моих глазах заключается в том, что мне приходится обрабатывать связь между агрегатами в этом сценарии, а также каждый раз, когда мне нужно проверить уникальность shortUrl Мне нужно прочитать все события из хранилища событий, чтобы создать всесообщения и это кажется сложным.
  2. Вторая альтернатива, которую я имею, - это когда событие запускается, и мой обработчик события, который создает модель чтения, запускает двойное короткое событие URL, когда замечает, что у него будет два коротких URL.это указывает на разные посты.Допустимо ли иметь модель чтения для запуска событий при обнаружении ошибок?

Есть ли еще альтернативы.Обратите внимание, что я знаю, что мой домен может не подходить для cqrs и DDD, но я делаю это для обучения в небольшом домене.

Ответы [ 3 ]

2 голосов
/ 30 ноября 2015

Я бы пошел на доменную службу, которая просто отвечает за генерацию уникальных ShortURL.Вы можете использовать транзакционную БД для реализации этого поведения.Обычно этот сервис будет использоваться частью обработки команд агрегата BlogPost.Если есть дубликат ShortURL, вы можете запустить DuplicateUrlErrorEvent.Вы можете предварительно отловить это в пользовательском интерфейсе (но не на 100%), создав тонкую модель запроса с использованием того же источника данных, чтобы вы могли запросить, является ли сокращенный URL-адрес уникальным, перед отправкой сообщения (как описано в ответе @ RyanR).

1 голос
/ 25 апреля 2017

Я прочитал различные ответы на этот и связанный с ним вопрос.

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

Однако, если вы хотите согласованности, вы должны использовать службу сохранения, которая имеетстрогая согласованность гарантирует.

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

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

Однако, поскольку у нас есть две транзакции, которые необязательно находятся в одной базе данных, мы можем потерпеть неудачу после первого принятия.Это нормально, потому что операция в целом также не будет выполнена.Хранилище чтения будет отражать несогласованное состояние в течение некоторого времени, но как только мы восстановим агрегат, хранилище чтения вернется в согласованное состояние.

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

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

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

0 голосов
/ 26 февраля 2012

Зависит от того, что хочет «бизнес». Если вы хотите, чтобы клиент (создатель команд) отвечал за выбор короткого URL-адреса, у него должно быть хранилище для чтения, из которого он проверяет его уникальность. Когда пользователь вводит короткий URL-адрес, представление должно проверить, что короткий URL-адрес является уникальным, и представить ошибку проверки, если это не так. Всякий раз, когда сообщение сохраняется, событие публикует обновленную информацию (включая короткий URL), которая синхронизирует хранилище для чтения.

...