Здравствуйте!
Был обнаружен баг, связанный с переиндексацией записей для системы поиска.
Суть бага в том, что при попытке переиндексировать сайт на соответствующей странице процесс индексации молча падает в ошибку и дальше не движется.
Эта заметка по сути багрепорт, а также небольшая инструкция, как можно временно починить переиндексацию, до выхода официального обновления.
Как воспроизвести баг?
Действия производятся на чистой установке в среде Битрикс VM. Версия дистрибутива: "1С-Битрикс: Корпоративный портал 21.400.100"
Приведу здесь полный текст ошибки:
Почему так происходит?
Когда мы удаляем задачу, по факту происходит не удаление, а сокрытие задачи. Она просто помечается как удаленная. В базе данных для этого существует флажок "ZOMBIE" в таблице "b_tasks". Он устанавливается в состояние "Y", если задача была удалена. Запомним этот момент.
Во время переиндексации данных, относящихся к модулю "Форум", запрашиваются в том числе и комментарии к задачам.
Комментарии проходят процедуру индексации и срабатывает обработчик события onMessageIsIndexed, находящийся в файле bitrix/modules/forum/lib/comments/taskentity.php.
У каждого комментария есть соответствующий ему идентификатор задачи (которая существует в базе данных).
В некоторых случаях для уточнения данных требуется запросить содержимое такой задачи при помощи метода CTasks::GetList, результат работы которого передается далее в метод CTasks::__GetSearchPermissions.
Он же в свою очередь вызывает метод CTasks::getMembers, приводящий к ошибке, так как на вход ожидается число (ID задачи), а передается NULL.
Это происходит из-за того, что в CTasks::__GetSearchPermissions приходит пустой массив, который возвращается нам из CTasks::GetList.
При этом в CTasks::__GetSearchPermissions не происходит никаких проверок на пустоту.
Получается, что передавая в CTasks::GetList гарантированно существующий ID задачи, на выходе мы получаем пустоту, как будто задачи нет.
Если проанализировать SQL запрос, который выполняет CTasks::GetList, то становится ясно, что проблема кроется в блоке WHERE.
Запись будет возвращена из базы только когда у неё совпадет ID, и только в случае если задача не была помечена как удаленная, то есть флаг ZOMBIE = "N".
Именно поэтому CTasks::GetList не будет возвращать данные по задаче, если она находится в статусе удаленной, несмотря на её фактическое присутствие в таблице.
Такое поведение не укладывается в текущую логику работы, так как мы рассчитываем, что CTasks::GetList всегда вернет какой-то адекватный результат по заданному ID задачи.
Как можно решить проблему?
Внимание! Это способ не является официальным решением и его применение производится на свой страх и риск, без каких-либо гарантий.
Самое простое, что можно предпринять - это заставить CTasks::GetList возвращать задачу независимо от её статуса.
Согласно документации, для этого в метод необходимо передать особый флаг.
Поэтому решить проблему можно путем изменения аргументов вызова CTasks::GetList в методе onMessageIsIndexed класса TaskEntity (он находится в ядре, по пути bitrix/modules/forum/lib/comments/taskentity.php).
Найдите там следующую строчку:
И измените её на такую:
Добавилась пара новых аргументов.
Третий аргумент принимает значение по-умолчанию и нужен для того чтобы из базы вернулись все доступные столбцы.
Четвертый аргумент как раз задает флаг, который позволит "видеть" удаленные задачи.
Таким образом, если задача находится в базе, она будет возвращена и дальнейший код отработает штатным образом.
Надеюсь, эта информация окажется полезной, как для людей, также столкнувшихся с нерабочей переиндексацией на портале, так и для команды разработчиков Битрикс в целях дальнейшего устранения проблемы.
Был обнаружен баг, связанный с переиндексацией записей для системы поиска.
Суть бага в том, что при попытке переиндексировать сайт на соответствующей странице процесс индексации молча падает в ошибку и дальше не движется.
Эта заметка по сути багрепорт, а также небольшая инструкция, как можно временно починить переиндексацию, до выхода официального обновления.
Как воспроизвести баг?
Действия производятся на чистой установке в среде Битрикс VM. Версия дистрибутива: "1С-Битрикс: Корпоративный портал 21.400.100"
- В разделе "Задачи и проекты" на портале создать новую задачу. Содержимое задачи не имеет значения;
- Добавить новый комментарий к задаче с произвольным содержимым от имени любого пользователя;
- Удалить задачу штатным образом;
- В настройках модуля "Поиск" перейти на страницу "Переиндексация" и запустить полную переиндексацию сайта (хотя баг проявляется и при переиндексации только измененных записей). Также можно запустить переиндексацию только для модуля "Форум", ошибка происходит в нём;
- В какой-то момент переиндексация "зависнет", в консоли разработчика можно будет увидеть 500 ошибку в скрипте /bitrix/admin/search_reindex.php?Reindex=Y&lang=ru&sessid=<здесь номер сессии>&max_execution_time=20&Full=N. Включите режим отладки на сервере для получения более подробного сообщения об ошибке.
Приведу здесь полный текст ошибки:
| Код |
|---|
[TypeError] Argument 1 passed to CTasks::getMembers() must be of the type int, null given, called in /home/bitrix/www/bitrix/modules/tasks/classes/general/task.php on line 6768 (0) /home/bitrix/www/bitrix/modules/tasks/classes/general/task.php:6658 #0: CTasks::getMembers(NULL) /home/bitrix/www/bitrix/modules/tasks/classes/general/task.php:6768 #1: CTasks::__GetSearchPermissions(array) /home/bitrix/www/bitrix/modules/forum/lib/comments/taskentity.php:161 #2: Bitrix\Forum\Comments\TaskEntity::onMessageIsIndexed(string, array, array) #3: call_user_func_array(array, array) /home/bitrix/www/bitrix/modules/forum/lib/comments/eventmanager.php:74 #4: Bitrix\Forum\Comments\EventManager::onMessageIsIndexed(string, array, array) /home/bitrix/www/bitrix/modules/main/classes/general/module.php:465 #5: ExecuteModuleEventEx(array, array) /home/bitrix/www/bitrix/modules/forum/classes/mysql/forum_new.php:205 #6: CForumNew::reindex(array, object, string) /home/bitrix/www/bitrix/modules/forum/classes/general/forum_new.php:1853 #7: CAllForumNew::OnReindex(array, object, string) /home/bitrix/www/bitrix/modules/main/classes/general/module.php:480 #8: ExecuteModuleEventEx(array, array) /home/bitrix/www/bitrix/modules/search/classes/general/search.php:1045 #9: CAllSearch::ReIndexAll(boolean, integer, array, boolean) /home/bitrix/www/bitrix/modules/search/admin/search_reindex.php:55 #10: require(string) /home/bitrix/www/bitrix/admin/search_reindex.php:2 |
Почему так происходит?
Когда мы удаляем задачу, по факту происходит не удаление, а сокрытие задачи. Она просто помечается как удаленная. В базе данных для этого существует флажок "ZOMBIE" в таблице "b_tasks". Он устанавливается в состояние "Y", если задача была удалена. Запомним этот момент.
Во время переиндексации данных, относящихся к модулю "Форум", запрашиваются в том числе и комментарии к задачам.
Комментарии проходят процедуру индексации и срабатывает обработчик события onMessageIsIndexed, находящийся в файле bitrix/modules/forum/lib/comments/taskentity.php.
У каждого комментария есть соответствующий ему идентификатор задачи (которая существует в базе данных).
В некоторых случаях для уточнения данных требуется запросить содержимое такой задачи при помощи метода CTasks::GetList, результат работы которого передается далее в метод CTasks::__GetSearchPermissions.
Он же в свою очередь вызывает метод CTasks::getMembers, приводящий к ошибке, так как на вход ожидается число (ID задачи), а передается NULL.
Это происходит из-за того, что в CTasks::__GetSearchPermissions приходит пустой массив, который возвращается нам из CTasks::GetList.
При этом в CTasks::__GetSearchPermissions не происходит никаких проверок на пустоту.
Получается, что передавая в CTasks::GetList гарантированно существующий ID задачи, на выходе мы получаем пустоту, как будто задачи нет.
Если проанализировать SQL запрос, который выполняет CTasks::GetList, то становится ясно, что проблема кроется в блоке WHERE.
Запись будет возвращена из базы только когда у неё совпадет ID, и только в случае если задача не была помечена как удаленная, то есть флаг ZOMBIE = "N".
Именно поэтому CTasks::GetList не будет возвращать данные по задаче, если она находится в статусе удаленной, несмотря на её фактическое присутствие в таблице.
Такое поведение не укладывается в текущую логику работы, так как мы рассчитываем, что CTasks::GetList всегда вернет какой-то адекватный результат по заданному ID задачи.
Как можно решить проблему?
Внимание! Это способ не является официальным решением и его применение производится на свой страх и риск, без каких-либо гарантий.
Самое простое, что можно предпринять - это заставить CTasks::GetList возвращать задачу независимо от её статуса.
Согласно документации, для этого в метод необходимо передать особый флаг.
Поэтому решить проблему можно путем изменения аргументов вызова CTasks::GetList в методе onMessageIsIndexed класса TaskEntity (он находится в ядре, по пути bitrix/modules/forum/lib/comments/taskentity.php).
Найдите там следующую строчку:
| Код |
|---|
$task = \CTasks::GetList(array(), array("ID" => $taskId))->fetch(); |
| Код |
|---|
$task = \CTasks::GetList(array(), array("ID" => $taskId), array('*'), array('bGetZombie' => true))->fetch(); |
Третий аргумент принимает значение по-умолчанию и нужен для того чтобы из базы вернулись все доступные столбцы.
Четвертый аргумент как раз задает флаг, который позволит "видеть" удаленные задачи.
Таким образом, если задача находится в базе, она будет возвращена и дальнейший код отработает штатным образом.
Надеюсь, эта информация окажется полезной, как для людей, также столкнувшихся с нерабочей переиндексацией на портале, так и для команды разработчиков Битрикс в целях дальнейшего устранения проблемы.