4

Прежде всего, позвольте мне сказать, что я новичок в разделении ответственности запросов запросов и событийных событий (архитектура Message-Drive), но я уже вижу некоторые существенные преимущества дизайна. Тем не менее, есть еще несколько вопросов, по которым я неясен.Каковы нарушения последовательности в обработчике событий?

Скажем, у меня есть класс Customer (совокупный корень), который содержит свойство postalAddress (экземпляр класса Address, который является объектом значения). У меня также есть класс Order (другой общий корень), который содержит (среди OrderItem объектов и т. Д.) Свойство, называемое deliveryAddress (также экземпляр класса Address) и строковое свойство, называемое status.

Клиент отправляет заказ, отправив команду PlaceOrder, которая вызывает событие OrderReceived. На данный момент статус заказа "RECEIVED". Когда заказ отправляется, кто-то на складе выдает команду ShipOrder, которая вызывает событие OrderShipped. На данный момент статус заказа "SHIPPED".

Один из бизнес-правил является то, что если Customer обновляет их postalAddress до того, как заказ будет отправлен (то есть, в то время как состояние еще "RECEIVED"), то deliveryAddress из Order объекта также должны быть обновлены. Если статус Order был уже "SHIPPED", то deliveryAddress не обновлялся.

Вопрос 1. Лучшее место для размещения этого «условно-каскадного обновления адреса» в саге (a.k.a., Process Manager)? Я так полагаю, учитывая, что он переводит событие («Клиент только обновил свой почтовый адрес ...») в команду («... так обновите адрес доставки порядка 123»).

Вопрос 2. Если сага является правильным инструментом для задания, как она идентифицирует заказы, принадлежащие пользователю, учитывая, что агрегат может быть получен только по его уникальному идентификатору (в моем случае UUID) ?

Продолжая, учитывая, что каждый агрегат представляет транзакционную границу, если бы система была врезаться послеCustomer «s postalAddress было обновлен (CustomerAddressUpdated события сохраняются в хранилище событий), но перед темOrderDeliveryAddressUpdated может быть обновлено (т. е. между двумя транзакциями), то система остается в противоречивом состоянии.

Вопрос 3. Как выявляются и исправляются такие «нарушения» правил согласованности?

ответ

3

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

Лучшее место для обработки этого процесса в менеджере процессов?

Да. У вас должен быть OrderProcess.

Как получить правильный экземпляр OrderProcess, учитывая, что он может быть восстановлен только с помощью идентификатора агрегата?

Нет ничего, что помешало бы добавить дополнительный механизм поиска, который связывает данные с агрегированным идентификатором. В моем экспериментальном, идущем-жить-скоро механизм называется shuttle-recall У меня есть механизм IKeyStore, который связывает любой произвольный ключ с AR-идентификатором. Таким образом, вы сможете связать что-то вроде [order-process]:customerId=CID-123; как ключ к некоторому агрегату.

Как выявляются и исправляются такие «нарушения» правил согласованности?

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

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

Только некоторые мысли :)

+0

Цените идеи. Я думал, что объект 'OrderProcessManager' может предоставить кэш/индекс (карту UUID-клиентов для вектора UUID-ордеров заказов для тех заказов, которые не были отправлены, таким образом, являются« stateful ») и когда' OrderProcessManager 'видит событие' OrderShipped', он просто удаляет UUID заказа из своего внутреннего кеша, но ваша идея о произвольных парах ключ/значение, хранящихся в хранилище событий, против совокупности является проницательной. – magnus

+0

'Как получить доступ к правильному экземпляру OrderProcess, учитывая, что его можно получить только с помощью идентификатора aggregate?' Wait ... вы говорите, что объекты Process Manager также хранятся в репозитории (например, хранится «OrderProcess» в «OrderProcessRepository» - с использованием ES, конечно) ??? – magnus

+0

Наличие 'OrderProcessRepository' * - это опция в настраиваемом мире реализации. если вы используете C#, я имею 3 реализации диспетчера процессов в [образцах моей служебной шины] (https://github.com/Shuttle/shuttle-esb-samples) в папке «Shuttle.ProcessManagement». Главное, что есть немного данных, которые вы собираетесь знать **, например, номер клиента. В обработке кода, создающей исходный поток, вы должны иметь доступ к этим данным, а в точке * * * вы должны создать связь между идентификатором AR и произвольным ключом. –