Всем привет. Подскажите, вот у меня есть слой Ui, откуда контроллер отправляет комманду в слой аппликации, который создает ивент, а потом проецирует его в нормализированную БД. Столкнулся с проблемой, когда случается коллизиция при создании одновременно двух одинаковых юзеров. Простыми словами, первый пользователь регистрируется, сохраняется ивент о регистрации и проецируется запись в нормализованную БД, а в это же время другой пользователь одновременно пытается зарегистрироваться под такими же данными и успевает проскочить сохранение ивента до того, как произойдет проецирование первого пользователя в нормализированную БД. В итоге получается, что у нас есть один нормально зарегистрированный пользователь и два ивента. Один из ивентов - правильный, и второй, который не валидный. Дело в том, что нельзя удалять ивенты, а можно только накатывать следующие. Если накатить еще один ивент для аггрегата о том, что пользователь уже создан, то это будет подразумевать, что этот ивент относится конкретно к контексту первого пользователя, а не к контесту второго. Как можно разрулить такую ситуацию?
Всё, решил проблему. Нужно сделать для транзакционных ивентов отдельный стрим. Все ивенты, которые могут подвергаться коллизии изначально сохранять туда, если эксепшина никакого нет при сохранении в нормализованную БД, то как-то делать линк этого события в основной стрим. Если же эксепшин есть, то эти ивенты так и будут оставаться в стриме для транзакции, никуда не будут вылазить и без разницы, какое количество невалидных ивентов создалось.
ивенты - это "факты", в отличии от команд, они говорят о том что уже случились (об истории).
вам нужно сначала создавать пользователя, потом записывать ивент о том что пользователь с таким-то айди создан.
Дело в том, что я не могу на прямую создавать в нормализованной базе данных пользователя, этим должен заниматься исключительно проектор(т.к. эта база исключительно для чтения). Я могу только проверить, что содержится или нет в ней такая запись. Да и к тому же, похожих моментов с коллизией обычно очень много в проектах случается и из-за этого код очень пованивать начинает...
P.S. Забыл еще добавить, что вся логика ES строится на том, что нам первичнее сохранить ивент, чем сохранить запись в нормализованную БД, т.к. если накроется последняя, то мы быстренько сможем из ивентов восстановить исходную БД, чего не сможем сделать, если накроется база с ивентами.
ну надо решить, что вы хотите записывать, Ивент Соурсинг, или Команд Соурсинг.
Если ивенты - то это уже случившиеся факты, которые произошли в прошлом, если команды - то это указание на то чтоб что-то сделать.
Если записываете команды -> типа "создать пользователя", то допускайте что команда может быть выполнена несколько раз (по разным причинам), чтоб это не вредило вводят процедуры дедубликации - обычно для этого к команде добавляется айдишник уникальный, по которому проверяется что команда уже была обработана, и в случае повторного вызова ничего не происходит, суть в том, чтоб вызов этой команды несколько раз, никак не менял результата в системе.
Если пользователь не создан, а ивент уже записан - то это не ивент, а лживое сообщение (изза этого у вас и проблемы).
⚡ Kotobotov ⚡, нету "командного сурсинга", как и нету "квери сурсинга", есть только ивент сурсинг=) Я тут вообщем немного поразмыслил и пришел к такой идее. Нужно сделать для транзакционных ивентов отдельный стрим. Все ивенты, которые могут подвергаться коллизии изначально сохранять туда, если эксепшина никакого нет при сохранении в нормализованную БД, то как-то делать линк этого события в основной стрим. Если же эксепшин есть, то эти ивенты так и будут оставаться в стриме для транзакции, никуда не будут вылазить и без разницы, какое количество невалидных ивентов создалось. Как-то так. Нужно пробывать.
RSalo,
допускаю что у кого-то чего-то нету.
ну вообще люди обсуждают, решают, с чем-то работают - https://gist.github.com/eulerfx/11227933
----
у ивентов нет колизий, тк ивенты я уже говорил - это факты в системе, которые уже случились в прошлом.
допускаю конечно что если переизобретать концепции, то все возможно, но вы все равно потом намучавшись придете к тому к чему уже люди давно пришли.
но видимо без мучений никак.
⚡ Kotobotov ⚡, я не совсем понял, что у них подразумевается под State. У меня сейчас так работает команда вызывает хандлер -> хандлер формирует состояние аггрегата -> измененные состояние аггрегата сохраняются в even store в виде ивентов -> потом есть проектор, в котором висят отдельные процессы в фоне, которые слушают измения в ивент сторе и при появлении новых ивентов проецирует их в нормализованную ДБ
Возможно, можно что-то улучшить...