308  /  381

Если долго сохраняется элемент в административном разделе

Просмотров: 462
Дата последнего изменения: 28.09.2020
Анна Кокина
Сложность урока:
4 уровень - сложно, требуется сосредоточится, внимание деталям и точному следованию инструкции.
1
2
3
4
5
Недоступно в редакциях:
Ограничений нет

  Проблема и её признаки

В этом уроке разберем решение периодически встречающейся проблемы, когда при работе в административном разделе элементы инфоблока сохраняются слишком долго.

Признаки:

  • долгое (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)-запрос к публичной детальной странице элемента, на которой в настройках компонента включено обновление счетчика просмотров.

Далее рассмотрим выявление причины подробнее на примере.

  Выявление причины

  1. Выявляем тормозящий запрос.

    В ходе первичного анализа установлено, что тормозящий запрос - это вызов метода ClBlockElement::CounterInc. Однако данный метод вызывается только для увеличения счетчика просмотров в публичных компонентах и не должен тормозить процесс сохранение элементов.

  2. Проверяем, как работает сохранение элемента.

    Открываем код страницы редактирования и видим, что сохранение элемента работает через транзакции. Делается это, чтобы откатить все изменения, если на каком-то этапе сохранения произошла ошибка.

  3. Проверяем вызовы методов.

    Последовательно проверяем все вызовы методов CIBlockElement::Update, обновление полей цен и товара, работу с документооборотом. , находящиеся внутри блока транзакции - есть ли на проекте обработчики событий, что именно вызывается в этих методах. Если результат отрицательный - разбираем методы детально и смотрим уже их (например, для метода CIBlockElement::Update таким является вызов CIBlockElement::UpdateSearch, а в нем - CSearch::Index).

    Важно! Учтите, в проекте могут быть и другие обработчики с вызовом api.

    В результате в одном из обработчиков находим http(s)-запрос к публичной детальной странице элемента. А на этой странице в компоненте Например, в компонентах Элемент каталога детально или Каталог включена опция Использовать счетчик просмотров. включено обновление счетчика просмотров. Отключаем его - все тормоза исчезают.

    Примечание: При открытии транзакции строка (а иногда и вся таблица) блокируется от записи. Это одна из причин, почему использование транзакций запрещено в методах api. Все попытки изменения записи, кроме текущей, ставятся в очередь ожидания на уровне базы. Пока транзакция не закрыта или не отменена - очередь ожидает.

Вывод: при редактировании элемента мы блокируем элемент от других изменений, но обработчик вступает в конфликт (пытается обратиться к обновленному счетчику). В результате элемент, созданный в административной части сайта, сохраняется долго (или может не сохраниться вообще).

Далее в уроке для наглядности рассмотрим ожидаемый план сохранения элемента и то, как на него влияет вызов подобных обработчиков.

  План сохранения данных без/с обработчиком

Ожидаемый план сохранения данных:

  1. Открываем транзакцию
  2. Обновляем строку в b_iblock_element
  3. Запись блокируется от внешнего изменения (другой хит) на уровне БД
  4. Закрываем транзакцию
  5. Запись разблокируется
  6. Выполняется очередь изменений с других хитов (если успела накопиться)

План сохранения данных с ранее выявленным обработчиком

  1. Открываем транзакцию
  2. Обновляем строку в b_iblock_element
  3. Запись блокируется от внешнего изменения (другой хит) на уровне БД
  4. Вызывается обработчик
  5. Идет хит на публичную страницу
  6. Пытаемся обновить счетчик просмотров (та же самая строка в b_iblock_element)
  7. ...долгое ожидание...

  8. Прерывание по таймауту. Обработчик завершен
  9. Если время исполнения скрипта не вышло - закрываем транзакцию. Вышло - просто "падаем"
  10. Запись разблокируется
  11. И тут, наконец, выполнится увеличение счетчика просмотров

Важно! Причины реализации подобных обработчиков могут быть разные. Тем не менее, в идеале на проекте их быть не должно. Это основная и главная рекомендация.

  Что делать, если обработчик нельзя убрать

Повторимся, что лучше не использовать в своем проекте обработчики событий, посылающие http(s)-запросы к публичной детальной странице элемента и вступающие в конфликт с выполнением транзакций.

Если по каким-либо причинам от такого обработчика избавиться нельзя, то можно воспользоваться следующими вариантами решения проблемы:

  1. Заменить прямое обращение к публичной странице на добавление в очередь обработки (своя таблица) и агента/скрипт на кроне, который пойдет по очереди и выполнит требуемое (обращение к странице и какие-то действия с результатом). Наиболее предпочтительный способ, однако его реализация требует высокого уровня знаний и квалификации разработчика.
  2. Передавать в строке обращения некий параметр (например,disableCounter=Y). На самой странице параметр вызова компонента USE_ELEMENT_COUNTER (на примере bitrix:catalog или catalog.element) меняем таким образом:
    • было:

      "USE_ELEMENT_COUNTER" => "Y"
      

    • стало:
      "USE_ELEMENT_COUNTER" => (isset($_REQUEST['disableCounter']) && $_REQUEST['disableCounter'] === 'Y') ? 'N' : 'Y'
      

    Этот способ проще первого, однако теряется возможность настройки компонента через визуальный редактор. Это можно поправить переносом правки в шаблон (в случае комплексного компонента).

0
Курсы разработаны в компании «1С-Битрикс»

Если вы нашли неточность в тексте, непонятное объяснение, пожалуйста, сообщите нам об этом в комментариях.
Развернуть комментарии