Если долго сохраняется элемент в административном разделе
Проблема и её признаки
В этом уроке разберем решение периодически встречающейся проблемы, когда при работе в административном разделе элементы инфоблока сохраняются слишком долго.
Признаки:
- долгое (60 секунд и выше) сохранение элемента/товара через форму редактирования в административном разделе (при импорте и обновлении из консоли проблема не наблюдается)
- анализ на стороне хостера выявляет долгий запрос вида:
UPDATE b_iblock_element SET
TIMESTAMP_X = TIMESTAMP_X,
SHOW_COUNTER_START = ifnull(SHOW_COUNTER_START, now()),
SHOW_COUNTER = ifnull(SHOW_COUNTER, 0) + 1
WHERE ID=ИД_сохраняемого_элемента
Наиболее вероятная причина - обработчик событий, посылающий http(s)-запрос к публичной детальной странице элемента, на которой в настройках компонента включено обновление счетчика просмотров.
Далее рассмотрим выявление причины подробнее на примере.
Выявление причины
- Выявляем тормозящий запрос.
В ходе первичного анализа установлено, что тормозящий запрос - это вызов метода ClBlockElement::CounterInc. Однако данный метод вызывается только для увеличения счетчика просмотров в публичных компонентах и не должен тормозить процесс сохранение элементов. 2. Проверяем, как работает сохранение элемента.
Открываем код страницы редактирования и видим, что сохранение элемента работает через транзакции. Делается это, чтобы откатить все изменения, если на каком-то этапе сохранения произошла ошибка. 3. Проверяем вызовы методов.
Последовательно проверяем все вызовы методов
CIBlockElement::Update, обновление полей цен и товара, работу с документооборотом. , находящиеся внутри блока транзакции - есть ли на проекте обработчики событий, что именно вызывается в этих методах. Если результат отрицательный - разбираем методы детально и смотрим уже их (например, для метода CIBlockElement::Update таким является вызов CIBlockElement::UpdateSearch, а в нем - CSearch::Index).
Важно! Учтите, в проекте могут быть и другие обработчики с вызовом api.
В результате в одном из обработчиков находим http(s)-запрос к публичной детальной странице элемента. А на этой странице в компоненте
Например, в компонентах Элемент каталога детально или Каталог включена опция Использовать счетчик просмотров. включено обновление счетчика просмотров. Отключаем его - все тормоза исчезают.
Примечание: При открытии транзакции строка (а иногда и вся таблица) блокируется от записи. Это одна из причин, почему использование транзакций запрещено в методах api. Все попытки изменения записи, кроме текущей, ставятся в очередь ожидания на уровне базы. Пока транзакция не закрыта или не отменена - очередь ожидает.
Вывод: при редактировании элемента мы блокируем элемент от других изменений, но обработчик вступает в конфликт (пытается обратиться к обновленному счетчику). В результате элемент, созданный в административной части сайта, сохраняется долго (или может не сохраниться вообще).
Далее в уроке для наглядности рассмотрим ожидаемый план сохранения элемента и то, как на него влияет вызов подобных обработчиков.
План сохранения данных без/с обработчиком
Ожидаемый план сохранения данных:
- Открываем транзакцию
- Обновляем строку в b_iblock_element
- Запись блокируется от внешнего изменения (другой хит) на уровне БД
- Закрываем транзакцию
- Запись разблокируется
- Выполняется очередь изменений с других хитов (если успела накопиться)
План сохранения данных с ранее выявленным обработчиком
- Открываем транзакцию
- Обновляем строку в b_iblock_element
- Запись блокируется от внешнего изменения (другой хит) на уровне БД
- Вызывается обработчик
- Идет хит на публичную страницу
- Пытаемся обновить счетчик просмотров (та же самая строка в b_iblock_element)
...долгое ожидание...
- Прерывание по таймауту. Обработчик завершен
- Если время исполнения скрипта не вышло - закрываем транзакцию. Вышло - просто "падаем"
- Запись разблокируется
- И тут, наконец, выполнится увеличение счетчика просмотров
Важно! Причины реализации подобных обработчиков могут быть разные. Тем не менее, в идеале на проекте их быть не должно. Это основная и главная рекомендация.
Что делать, если обработчик нельзя убрать
Повторимся, что лучше не использовать в своем проекте обработчики событий, посылающие http(s)-запросы к публичной детальной странице элемента и вступающие в конфликт с выполнением транзакций.
Если по каким-либо причинам от такого обработчика избавиться нельзя, то можно воспользоваться следующими вариантами решения проблемы:
- Заменить прямое обращение к публичной странице на добавление в очередь обработки (своя таблица) и агента/скрипт на кроне, который пойдет по очереди и выполнит требуемое (обращение к странице и какие-то действия с результатом). Наиболее предпочтительный способ, однако его реализация требует высокого уровня знаний и квалификации разработчика.
- Передавать в строке обращения некий параметр (например,
disableCounter=Y). На самой странице параметр вызова компонентаUSE_ELEMENT_COUNTER(на примере bitrix:catalog или catalog.element) меняем таким образом: -
было:
- стало:
Этот способ проще первого, однако теряется возможность настройки компонента через визуальный редактор. Это можно поправить переносом правки в шаблон (в случае комплексного компонента).