2 водителей
2. На одного водителя не больше не 3 машин
3. Нельзя удалить машину, если у неё есть как минимум 1 водитель
Юзкейсы
1. Добавить машину
2. Удалить машину (соблюдая правило 3)
3. Добавить водителя
4. Удалить водителя
5. Зарегистрировать машину за водителем (соблюдая правила 1 и 2)
Есть ли возможность это всё смоделировать так, что у нас везде будет transaction consistency (соблюдая правило, один агрегат на транзакцию), и при этом не будет одного жирного агрегата?
2 агрегата. 1. машина айди + водители айдис 2. водитель айди + машины айдис Их хватит чтобы покрыть все 3 инварианта
А в каком из каждых агрегатов должно проверяться каждое из инвариантов?
Бизнес правила: 1. На одну машину не больше 2 водителей ---- в первом 2. На одного водителя не больше не 3 машин --- во втором 3. Нельзя удалить машину, если у неё есть как минимум 1 водитель --- в первом
Тогда, чтобы реализовать этот юзкейс: 5. Зарегистрировать машину за водителем (соблюдая правила 1 и 2) Мне нужно в рамках одной транзакции работать с двумя агрегатами? т.е. менять стейт двух агрегатов в одной транзакции
Я бы сделал eventuell consistency. Регистрировал паралельно и там и там и в случае неуспеха подчищал. Вряд ли там будет высококонкурентный процесс. Так что такое не должно случатся практически никогда.
То что вам насоветуют с consistency, зависит конкретно от лоада
Меня интересует возможность реализации этого кейса конкретно при помощи transaction consistency и чтобы в рамках одной транзакции не менялся стейт нескольких агрегатов (при этом не создавая ожин жирный агрегат на все случаи)
тут важно еще какая вероятность что возникнет гонка. Если она незначительна - то есть лочить мы будем только отдельные агрегаты - то достаточно просто взять из базы два агрегата через select for update, и обновить их в одной транзакции. Таким образом избегаем необходимости в эвеншуал консистенс
в целом, если убрать ограничение транзакционной консистентности, что мы можем придумать... - добавить машину - тут нет возможности сломать инварианты. То же про "добавить вобителя". Их игнорим. - удалить водителя - тут по сути тоже, удаляется водитель и как следствие снимается регистрация (хотя я бы это уточнил). Тут нет особо возможности операции упасть из-за бизнес штук. я бы это просто вынес в очереди и retry on failure сделают свое черное дело - зарегистрировать машину за водителем - тут можно пойти на хитрость. Для начала мы закрепляем чет типа заявки за водителем. В рамках этого агрегата мы будем форсить правило номер 2. Если зафэйлилась операция - значит зафэйлилась. Дальше второй агрегат связывает водителя и авто, так форсим первое правило. Если оно зафэйлилось - то значит надо снять заявку. Это можно все делать eventually через ивенты - в худшем случае какое-то небольшое время человека нельзя будет зарегать за машиной, но стэйт разрулится. - ну и удаление авто - тут опять же мы храним список водителей за которыми зарегистрирована машина и в целом уже все хорошо. то есть по факту только операция регистрации водителя требует более одного агрегата на транзакцию и eventual consistency. за счет того что мы сначала резервируем слот а потом регистрируем система не может войти в невалидное состояние, нам легко потом будет откатиться.
> один агрегат на транзакцию для этой операции не выйдет просто в силу характера many-to-many ассоциаций А есть статьи или, может, где-то в книжке написано, по этой проблеме?
Чё за язык красивй?
Агрегаты по своей сути документы, и атомарность изменения стэйта можно гарантировать только в пределах одного документа за раз. Моделировать many-to-many через документы не выйдет. В этом как бы секрет успеха реляционных баз данных
скорее всего TypeScript
Да, можно, но у автора было требование "одна транзакция один агрегат". Это увы нельзя с many to many. Тут будет одна транзакция два агрегата.
А нельзя сделать новый агрегат, где будет массив carIds по водителю. И driverIds по машине?
Обсуждают сегодня