Я понимаю, что вышеупомянутый вопрос, вероятно, поднимает несколько вопросов «что?», Но позвольте мне попытаться объяснить:
Я пытаюсь обдумать несколько взаимосвязанных концепций, в основном шаблон Saga ( http://www.rgoarchitects.com/Files/SOAPatterns/Saga.pdf ) в сочетании с Event-sourcing (DDD-концепция). : http://en.wikipedia.org/wiki/Domain-driven_design )
Хороший пост, который объединяет его: https://blog.jonathanoliver.com/cqrs-sagas-with-event-sourcing-part-ii-of-ii/
Я подойду к вопросу через минуту, но я думаю, что сначала я должен попытаться суммировать то, что я понимаю о нем (что может быть неправильно, поэтому, пожалуйста, исправьте, если это так), так как это может повлиять на то, почему я задать вопрос для начала:
- Шаблон Saga - это своего рода брокер, который дает действию (конечному пользователю, автоматизированному и т. Д. Практически все, что собирается изменить данные), разделяет это действие в бизнес-действиях и отправляет каждое из этих действий в виде сообщений в шину сообщений, которая в свою очередь отправляет его в соответствующие совокупные корни, о которых нужно позаботиться.
- Эти совокупные корни могут работать полностью автономно (хорошее разделение задач, отличная масштабируемость и т. Д.)
- Сам Saga-экземпляр не содержит никакой бизнес-логики, которая содержится в агрегатных корнях, в которые он отправляет действия. Единственная «логика», содержащаяся в саге, - это «логика процесса» (часто реализуемая как Statemachine), которая на основе полученных действий (а также последующих событий) определяет, что делать (т.е. какие действия отправлять)
- Saga-шаблоны реализуют своего рода шаблон распределенных транзакций. То есть: когда один из агрегатных корней (которые снова работают автономно, не зная о существовании друг друга), терпит неудачу, все действие, возможно, придется откатить.
- Это достигается за счет наличия всех совокупных корней, после завершения отчета о деятельности они возвращаются в Сагу. (В случае успеха, а также ошибки)
- В случае, если все совокупные корни возвращают успех, внутренняя машина состояний, если Saga определяет, что делать дальше (или решает, что сделано)
- В случае неудачи Сага выдает всем совокупным корням, которые принимали участие в последнем действии, так называемое Компенсационное действие, то есть: действие, чтобы отменить последнее действие, которое выполнил каждый из совокупных корней.
- Это может быть просто «минус 1 голос», если действие «плюс 1 голос», но это может быть более сложным, чем восстановление блога в предыдущей версии.
- Источник событий (см. Объединение этих двух статей в блоге) направлен на сохранение результатов всех действий, выполняемых каждым из агрегатных корней, в централизованном хранилище событий (в этом контексте изменения называются «событиями»).
- Это хранилище событий является «единой версией правды» и может использоваться для воспроизведения состояния всех объектов, просто повторяя сохраненные события (по сути, как журнал событий).
- Комбинация двух (то есть: предоставление агрегированным корням возможности использовать Event-Sourcing для передачи своих изменений перед передачей отчета в Saga) дает много хороших возможностей, одна из которых касается моего вопроса
Я почувствовал, что мне нужно снять это с плеча, так как это можно понять сразу. Учитывая этот контекст / мышление (опять же, пожалуйста, исправьте, если не так)
вопрос: когда агрегатный корень получает действие Compensate и если этот агрегатный корень передал на аутсорсинг свои изменения состояния с использованием Event-sourcing, не будет ли действие Compensate Action во всех ситуациях просто удалением последнего события в хранилище событий для этого данный совокупный корень? (Предполагая, что постоянная реализация позволяет удалять)
Это имело бы для меня большой смысл (и было бы еще одним большим преимуществом этой комбинации), но, как я уже сказал, я могу делать эти предположения на основе неправильного / неполного понимания этих концепций.
Я надеюсь, что это не слишком затянуто.
Благодарю.
Для полноты я подумал включить соответствующий фрагмент от Мартина Фаулера о способах возврата состояния:
От: http://martinfowler.com/eaaDev/EventSourcing.html
источник
Концептуально:
Мы можем изменить наше будущее состояние, только выполнив другую команду (Compensate Action), которая должна привести к тому, что события изменят состояние приложения.
Чтобы «сбить с толку» вопрос, подумайте над фразой «удалить последнее событие»:
Короче говоря, у вас нет возможности удалять события в шаблоне CQRS.
Вы можете уменьшить свой Event Store, создав состояние моментального снимка (который основан на всех событиях, ведущих к этому состоянию), но этот физический аспект не имеет ничего общего с концепцией события.
источник
Герт-Ян, я тоже думаю, что действие компенсации может просто удалить соответствующее событие (я). Это имеет смысл и показывает еще одно преимущество шаблона проектирования Event Sourcing: более простую реализацию шаблона проектирования Compensating Transaction.
Некоторые говорят, что удаление события нарушает «принципы» поиска событий или CQRS. Я думаю, что это ограничивающее обобщение. Я думаю, что можно удалить событие, если оно было создано в рамках глобальной транзакции, которая отменяется. Рассмотрим псевдокод:
Предположим, что ваше хранилище событий является транзакционной базой данных. В псевдокоде вы можете представить ситуацию, когда вы вставили первое событие, но при попытке вставить второе событие было сгенерировано исключение. Команда отката, естественно, вернет вставку первого события. Это разумно?
Если это целесообразно для транзакции базы данных ACID (транзакция с фиксацией / откатом), почему она не подходит для компенсирующей транзакции?
При выполнении глобальной транзакции Saga изменения данных могут быть отменены (путем компенсации). Нет необходимости сохранять событие, созданное во время транзакции, поскольку транзакция не завершена.
Теперь, если компенсация пытается удалить событие, и это событие не является новейшим событием на объекте, удаление не должно происходить. Но в целом это вряд ли произойдет, особенно в решениях с интенсивным чтением.
источник
Давайте поиграем с мыслью, что хранилище событий - это просто данные, которые вы хотите сохранить. Например, у нас может быть жесткий диск, мы можем начать с самого начала и записать на него данные. Каждый раз, когда мы получаем событие, мы добавляем наши предыдущие данные, поэтому мы просто продолжаем записывать на диск, на котором остановились в прошлый раз. Когда мы хотим удалить событие, мы возвращаемся, удаляем эту часть с диска и оставляем пробел. Перемещение назад само по себе замедляет наше хранилище событий, но мы можем с этим смириться. Если мы используем файловую систему, она будет пытаться заполнить пробел последними событиями, поэтому у нас будет медленно фрагментированное хранилище, или мы можем выполнить дефрагментацию. Ни один из них нам не нравится. Если мы говорим о базах данных, вы получите это, если вы будете использовать реляционную базу данных вместо базы данных только для добавления для хранения ваших событий:
ссылка: https://cambridge-intelligence.com/bringing-time-series-data-to-life-with-keylines/
Ofc. для обычного сайта это не имеет значения, но эти решения предназначены для огромных веб-сайтов, таких как Facebook, Google и т. д. Так что на самом деле вопрос не имеет смысла, потому что, как бы вы удалили событие в базе данных только для добавления и как бы Вы называете компенсацию чем-то вроде создания машины времени и возврата во времени, чтобы изменить или предотвратить событие ???
Насколько мне известно. единственный способ решить эту проблему - создать новое хранилище событий, в котором вы исключаете события, которые вы не хотите иметь, и после этого удаляете старое хранилище событий. Но это экстремальное решение для удаления одного события. Если мы говорим о GDPR, то единственное относительно хорошее решение, которое я знаю, - это хранение личных данных, зашифрованных в хранилище событий, и удаление ключа шифрования из другой базы данных.
источник