Я хотел бы иметь простую реализацию CQRS в API. Суммируя:
После выполнения команды, естественно, мне нужно вызвать событие и передать его в шину событий. Шина событий обработает событие и передаст его своим подписчикам. В этом случае подписчиком является модель чтения, которую необходимо обновить.
Поэтому мне нужен маршрут обратного вызова в API, который получает событие из командной шины и обновляет проекцию модели чтения (т.е. обновляет денормализованную таблицу БД, которая используется для запросов).
Проблема в том, что обновление проекции модели чтения не является ни командой (мы не выполняем никакой логики предметной области), ни запросом.
Вопросы: Как должно работать это обновление асинхронной модели чтения, чтобы обеспечить совместимость как с CQRS, так и с DDD?
Как должно работать это обновление асинхронной модели чтения, чтобы обеспечить совместимость как с CQRS, так и с DDD?
Обычно я думаю о потоке информации как о треугольнике.
Общий язык для этого промежуточного шага - «проекция».
Таким образом, проекция (обычно) выполняется асинхронно, запрашивая «модель записи» и обновляя «модель чтения».
В изложенной вами архитектуре это будет проекция, которая подписана на шину. Когда шина сигнализирует об изменении модели записи, мы пробуждаем проекцию и позволяем ей работать, чтобы она могла обновить модель чтения.
(Обратите внимание на поток информации — сигнал, который мы получаем от шины, запускает проекцию, но проекция копирует данные из модели записи, а не из сообщения шины событий. Это не единственный способ упорядочить вещи, но он прост, и поэтому его легко рассуждать, когда дела начинают идти не так, как надо.)
Часто бывает так, что проекция сохраняет некоторые собственные метаданные при обновлении модели чтения, чтобы не повторять работу.
Если вы считаете, что маршрут обратного вызова является важной частью вашего вопроса, вы можете попытаться прояснить свою проблему. Я не совсем понимаю мысль, которую вы пытаетесь здесь выразить.