Итак, что мне не хватает?
Догадываюсь
Первое, что вы можете упустить, это то, что вам нужно только перезагрузить события для состояния, которое вы восстанавливаете. Если вы можете четко смоделировать границы транзакций, каждый объект может записывать события, помеченные его собственным идентификатором, а затем считывать только эти события. Используя реляционную базу данных для хранения событий, для ускорения этого запроса был бы индексированный столбец идентификаторов. Используя EventStore, каждый объект будет иметь свой собственный поток.
В вашей модели требуется некоторая осторожность, чтобы сделать это аккуратно, поскольку вы хотите быть уверены, что вы изменяете только один объект в каждой транзакции, и поэтому вам нужно позаботиться о том, чтобы правильно изолировать каждый инвариант, который вы пытаетесь соблюдение.
В случаях, когда это недостаточно быстро, у вас все еще есть возможность создавать снимки своего состояния (памятки) и сохранять их в «традиционном хранилище». Каждый снимок помечается порядковым номером последнего события, использованного для создания снимка; при перезагрузке хранилище сначала получает этот снимок, а затем применяет к нему новые события. (Это подразумевает некоторый разумный способ получения более свежих снимков - либо события также помечаются порядковым номером, либо у вас есть какой-то эффективный способ чтения потока событий в обратном направлении, пока вы не достигнете своей начальной точки.)
Здесь по-прежнему есть преимущество перед обычным подходом, заключающимся в том, что ваши снимки могут быть построены параллельно с вашими записями, а не объединены с ними: вы просто помещаете прослушиватель событий в какой-то другой поток / процесс и позволяете ему весело писать вместе с записью в магазине снимков по любому графику, который кажется разумным. В конце концов, снимок не должен быть особенно своевременным - достаточно часто, чтобы работа по повторному применению новых событий не взорвала ваш SLA.
(Моментальные снимки усложняют миграцию; любые изменения в сериализации модели приведут к аннулированию кэша моментальных снимков. Конечно, вы можете перестроить моментальные снимки, используя новую сериализацию как часть миграции, а затем «догнать», когда изменения вступят в силу.)
Восстановление состояния из потока событий вообще обычно выполняется?
Да, это так. Что обычно показано в примерах CQRS, так это то, что прикладной уровень после проверки правильности сформированной команды прикладной уровень загружает объект домена из репозитория, где загрузка является конструктором по умолчанию, за которым следует воспроизведение потока событий. (или, что то же самое, вызов фабрики со списком событий).
Две другие противоречивые мысли.
- Там может быть кэш позади интерфейса хранилища
- Аннулирование кэша является одной из двух сложных проблем.