Pull to refresh

Comments 8

Удачи! Надеюсь, следующая статья будет уже о практических испытаниях на живом MODX. Всё-таки самое интересное — посмотреть, что из этого получится в реальных условиях. Теория и тесты — это хорошо, но практика иногда преподносит такие сюрпризы, что мало не покажется.

Спасибо. Надеюсь, что в скором времени что-то смогу написать и об этом.

Я поймал похожую историю с повторами в своей обвязке API. Пакетная отправка создала задания, но ответа не дождалась: сервис поставил их на паузу из-за нехватки баланса. Дальше включилась поштучная отправка и создала те же задания заново. Вместо 16 запросов в очереди оказалось 32. Теперь я сохраняю идентификатор уже созданного задания, чтобы поштучный путь забирал его, и останавливаю канал, если сервис сообщает о паузе.

Вот здесь, кстати, интересный момент. Таймаут ведь ещё не означает, что операция не выполнилась. Поэтому я бы разделял состояния FAILED и UNKNOWN. Если подтверждение не пришло, это ещё не повод запускать поштучную отправку. Сначала неплохо бы выяснить судьбу первоначального запроса, если API это позволяет.

А у вас есть возможность проверить, какие именно задания создались, если пакетный запрос вообще не вернул ответа? Или приходится ориентироваться только на локально сохранённые идентификаторы?

Тут, по-моему, проблема чуть глубже. У вас два механизма отправки независимо создают задания. Я бы разделил создание задания и его отправку: единый реестр с уникальными ключами и состояниями, а пакетная и поштучная отправка — просто разные способы доставки.

При потере ответа задание переходит в UNKNOWN, а не создаётся заново. При ошибке баланса срабатывает circuit breaker. Правда, без поддержки идемпотентности на стороне API полностью исключить дубли всё равно не получится. Вот это уже интересная задачка.

В tv_stale_guard правка человека появляется до сравнения. На тестовой копии MODX с MySQL можно запустить запрос с ожидаемым значением TV и поставить его на паузу сразу после успешного сравнения, перед записью. Из второго сеанса сохранить другое значение этого поля через админку. Если сохранение прошло, продолжить первый запрос и проверить, что он сообщает о конфликте, а чтение из отдельного сеанса показывает правку второго. Если админка ждёт блокировку, стоит зафиксировать это как отдельный исход и ограничить время ожидания, чтобы тест не завис.

Да, тут я проверил только сам конфликт до записи. А что будет, если человек успеет сохранить правку прямо между сравнением и записью, пока не проверял.

На тестовой копии это можно поймать. Приостановить запрос сразу после сравнения, поменять TV через админку и потом продолжить. Посмотреть, вернёт ли он STALE_STATE и останется ли в базе правка человека. Если админка зависнет в ожидании блокировки, это тоже надо записать отдельно, а то тест можно надолго подвесить. Добавлю такую проверку, когда доберусь до MODX с MySQL.

Я бы не рекомендовал напрямую вмешиваться в MySQL, особенно через AI-агента. Так можно обойти API MODX, события и механизмы кеширования. Лучше тестировать через штатный API MODX и админку. А проблему конкурентного редактирования решать через optimistic locking, проверку версии данных непосредственно при записи.

Кстати, в ResourceTvUpdateTool проверка expected_tvs выполняется до начала транзакции. Поэтому окно для race condition остаётся. Даже транзакция здесь сама по себе не спасает.

Sign up to leave a comment.

Articles