Сага, которые зависят от событий из прошлого
У меня есть вопрос, как бороться с сагой, где принятие решения зависит от события, которое было опубликовано до создания саги.
Вот пример, чтобы проиллюстрировать мою проблему:
Представьте, что у меня есть CustomerAR и OrderAR. Когда customerAR создается, начинается процесс проверки, результатом которого является сумма заказа, которую клиент может потратить без специальной авторизации. Я не буду вдаваться в подробности об этом процессе, потому что он вне контекста. Когда сумма рассчитывается, в CustomerAR отправляется команда с рассчитанной суммой, а CustomerAR публикует событие (CustomerMaxOrderAmountEvent) с этим значением. Все идет нормально.
Затем через несколько недель клиент размещает заказ. OrderAR создан и запускает мою OrderSaga. Сага ждет, пока заказ не будет создан полностью, а затем должна принять решение, если ей нужно отправить AutorizationCommand для этого заказа. Чтобы принять это решение, он должен знать, опубликовано ли CustomerMaxOrderAmountEvent и значение суммы. Обычно OrderSaga также подписывается на CustomerMaxOrderAmountEvent, но проблема в том, что это событие никогда не произойдет, потому что оно уже произошло в прошлом.
Как мне с этим бороться. Если я запрашиваю модель чтения, чтобы узнать значение, должен ли я отправить команду для получения значения, должен ли я сделать ссылку на CustomerAR, должен ли я воспроизвести все исторические события в саге, чтобы он уже знал историю.
ОБНОВИТЬ
Обратите внимание, что речь идет о концепции, а не об этом конкретном примере. Этот пример является чистым для прояснения проблемы: "2 несвязанных агрегатных корня, которые не являются частью одного и того же ограниченного контекста".
Благодарен за помощь.
Melvin
2 ответа
Я бы пошел для более простого решения - просто добавьте эту информацию (например, в виде HasCustomerReachedMaxOrderAmount
) к событию, которое начинает сагу.
Второй вариант, который я бы выбрал, - это подготовить модель чтения, предназначенную для использования с Sagas, и оттуда запросить данные, но я собрал бы всю необходимую информацию еще до запуска саги. Это обогащение может быть выполнено обработчиком исходного события, вызванного AR, поскольку это не является частью агрегированного / ограниченного контекста.
Однако в большинстве случаев достаточно опираться на данные, передаваемые с событиями, потому что Sagas должен содержать бизнес-логику только в форме процесса. Это очень часто означает, что у вас может быть более одной саги (следовать вашему примеру OrderSaga
а также OrderWithMaxAmountSaga
).
С учетом всего сказанного, учитывая приведенный вами пример сценария, я думаю, что решение о том, требует ли заказ авторизацию или нет, должно быть частью самого вашего домена и приниматься во время запуска саги.
Я бы смоделировал этот сценарий так: CustomerAR
рассчитывает максимальную сумму; клиент размещает заказ -> OrderAR
создается с информацией о максимальной сумме для этого клиента, Order
проверяет необходимость дополнительной авторизации -> Saga
начать. Дело в том, что информация о максимальной сумме важна как для CustomerAR
(где это может измениться) и OrderAR
(где он неизменен).
Я только начинаю баловаться с DDD, и я не собираюсь повторять то, что сказал kstaurch, но вот некоторые мысли, которые я думал о вашем сценарии:
Как насчет того, чтобы сделать максимальную сумму заказа частью платежной информации? Это должно быть где-то получено, и я уверен, что вы позаботитесь о состоянии, в котором обработка платежей отклонена.
Что если сага всегда посылает команду авторизации, но именно часть авторизации обрабатывает экран максимального заказа? Если вы говорите "Если сумма превышает $X, то получите авторизацию", возможно, ваша бизнес-модель также думает об этом как "Если она ниже $X, автоматически одобрите". Преимущество заключается в том, что все вопросы об утверждении (в том числе о том, следует ли получать одобрение) могут быть перенесены в объект утверждения или в саги.