Я все еще борюсь с основными (и решаемыми) проблемами, связанными с архитектурой стиля CQRS:
Как мы реализуем бизнес-правила, основанные на наборе совокупных корней?
Возьмем, к примеру, заявку на бронирование. Это может позволить вам забронировать билеты на концерт, места для фильма или столик в ресторане. Во всех случаях на продажу будет выставлено ограниченное количество предметов.
Давайте представим, что событие или место очень популярны. Когда продажи открываются для нового события или временного интервала, резервирования начинают поступать очень быстро - возможно, много в секунду.
На стороне запроса мы можем масштабироваться, и резервирование ставится в очередь для асинхронной обработки автономным компонентом. Сначала, когда мы извлекаем команды резервирования из очереди, мы принимаем их, но в определенный момент нам придется начинать , отклоняя остальные .
Как мы узнаем, когда достигнем предела?
Для каждой команды резервирования нам нужно будет запросить какое-то хранилище, чтобы выяснить, сможем ли мы удовлетворить запрос. Это означает, что нам нужно знать, сколько бронирований мы уже получили в то время.
Однако, если хранилище доменов является хранилищем нереляционных данных, таким как, например, Windows Azure Table Storage, мы не очень хорошо можем сделать SELECT COUNT(*) FROM ...
Один из вариантов - сохранить отдельный Aggregate Root , который просто отслеживает текущий счет, например:
- АР: Бронирование (кто? Сколько?)
- AR: Событие / Временной интервал / Дата (общее количество)
Второй Aggregate Root был бы денормализованным агрегированием первого, но когда базовое хранилище данных не поддерживает транзакции, тогда весьма вероятно, что они могут быть не синхронизированы в сценариях большого объема (что мы и делаем пытаемся обратиться в первую очередь).
Одним из возможных решений является сериализация обработки команд резервирования так, что обрабатывается только по одной за раз, но это идет вразрез с нашими целями масштабируемости (и избыточности).
Такие сценарии напоминают мне о стандартных сценариях «нет в наличии», но разница в том, что мы не можем очень хорошо оформить резервирование в обратном порядке. После того, как событие распродано, оно распродано, поэтому я не вижу, какое будет компенсационное действие.
Как мы справляемся с такими сценариями?