Pull to refresh

Comments 8

Фикс

Ну и странный какой-то фикс. Почему мы юзера удаляем мягко, а запись из листа ожидания - жёстко?

У каждого компонента было своё определение «удалённый пользователь». У некоторых его не было вообще.

Ну бардак он и есть бардак.

Здесь код promoteFromWaitlist написан правильно — он делает именно то для чего предназначен: находит первого в очереди без активного appointment и продвигает его.

А если продолжить "... плюя на всё" - то уже как-то возникают сомнения в правильности. Своё сделал, а там хоть трава не расти.

PS. Stored procedures.

Спасибо за комментарий.

Согласна, что показанный фикс решает только конкретный сценарий с waitlist и сам по себе не отвечает на вопрос, что делать с остальными связанными сущностями.

Наверное, моя формулировка про то, что “promoteFromWaitlist написан правильно” была слишком категоричной. Точнее было бы сказать, что функция была написана в соответствии со своими локальными правилами и не учитывала состояние deletedAt. Именно это расхождение между локальной логикой компонентов и привело к появлению ghost appointment.

Собственно, это и было основным наблюдением из инцидента: soft delete существовал на уровне users, но не был частью общего контракта системы.

Мы тоже используем у себя мягкое удаление. И тоже, то что казалось идеальным решением стало небольшим геморроем, только у нас в этой же таблице есть еще и “архивные” записи с точно такой же логикой. Там где мы используем ORM еще можно использовать глобальные фильтры… но часть логики у нас сознательно протекла в хранимые процедуры SQL Server… ради скорости, и там приходится обмазываться фильтрами в каждом запросе.

Корневая проблема – не в том, что фильтров много, а в том, что в одной таблице живут три разных типа сущности: активная, мягко удалённая и архивная. ORM-фильтры и хранимые процедуры – это ручная компенсация отсутствующего типа. Выход: view `active_users` + `archived_users` поверх одной таблицы со status-колонкой enum – и SQL-сторона перестаёт «протекать».

Корневая проблема – не в том, что фильтров много

Корневая проблема в том, что наш продукт родился из эксельки с макросами… где зафигачить дополнительную колонку в таблицу оказалось быстрым и приемлимым решением. Так далеко никто не загадывал.

Выход

Я надеюсь что когда-нибудь наш стек будет помечен как “неприемлимо устаревший”, а сейчас он просто устаревший… и придется все переписать на Postgres с нормальными архитектурными решениями. Вопрос только в том не закончится ли жизненный цикл продукта раньше, чем это случится ))

Порядок важен: если сначала выставить deletedAt, а потом чистить вейтлист — в промежутке может сработать ...

А ещё существуют транзакции...

Если при выполнении подобных действий вы их не используете, то вас ждёт ещё много сюрпризов.

Согласна. В статье я сфокусировалась на семантике soft delete и недостаточно раскрыла вопрос атомарности операции.

В реальной реализации такие изменения действительно должны выполняться в транзакции. Моя мысль была скорее о том, что даже при корректной технической реализации остаётся вопрос бизнес-семантики: что именно означает “удалить пользователя” для waitlist, appointment и других связанных компонентов.

Sign up to leave a comment.

Articles