В MySQL 8 поломались скрипты, которые определяли размер таблиц.
Переменная information_schema_stats_expiry теперь не 0, а 84600 по умолчанию. Информация из information_schema.tables обновляется раз в сутки.
Мы не знаем, что таблица большая или маленькая. Мы не можем из-за кеша адекватно оценить размер будущего бекапа. Мы не можем почистить переполненные таблицы.
Решение проблемы - надо сделать запрос SET SESSION information_schema_stats_expiry = 0; , перед тем, как читать таблицу.
Делать FLUSH TABLES и подобные манипуляции не нужно. Кеш для information_schema.tables - про другое
$connection = \Bitrix\Main\Application::getConnection($connection_name);
$database_name = $connection->getDatabase();
$query = "SET SESSION information_schema_stats_expiry = 0;";
$dbResult = $connection->query($query);
$query = "SEL ECT table_name AS table_name, data_length AS total_size, table_rows as table_rows
FR OM information_schema.tables WHERE table_schema = '$database_name' AND table_name = '$table_name';";
$rs = $connection->query($query);
$arInfo = $rs->fetch();
В примере выше добрый сайт битрикса вставил пробелы в слова sel ect и fr om. Надо без пробелов, конечно.
При операциях записи в ORM очень важно проверять получившийся результат.
Пример Warning
$result = \Bitrix\Catalog\Model\Price::delete($arFields["ID"]);
$result->__destruct();
// Warning. Потому что произошла ошибка, и не сделали $result->isSuccess(), $result->getErrors(), $result->getErrorMessages()
Warning: CAskaronMyTest: запрещено удалять значение цены in /bitrix/modules/main/lib/orm/data/result.php on line 87
Call Stack
# Time Memory Function Location
{main}( ) .../test5.php:0
Bitrix\Main\ORM\Data\Result->__destruct( ) .../test5.php:65
trigger_error( $message = 'CAskaronMyTest: запрещено удалять значение цены', $error_level = 512 ) .../result.php:87
Пример вызова - обработчик ORM D7 перед удалением значения цены
Warning получается если метод ORM вернул результат с ошибкой, и мы не проверили результат.
$eventManager = \Bitrix\Main\EventManager::getInstance();
$eventManager->addEventHandler("catalog", "Bitrix\\Catalog\\Model\\Price::OnBeforeDelete",
array("CAskaronMyTest", "PriceOnBeforeDelete"),
false,
50
);
class CAskaronMyTest {
public static function PriceOnBeforeDelete( \Bitrix\Main\Event $event )
{
$result = new \Bitrix\Main\Entity\EventResult();
$arErrors = array();
$arErrors[] = new \Bitrix\Main\Entity\EntityError(
__CLASS__.": запрещено удалять значение цены"
);
$result->setErrors($arErrors);
return $result;
}
}
// Удалить цены для товара
$PRODUCT_ID = 15709;
if ( \Bitrix\Main\Loader::includeModule( "catalog" ) )
{
$res = \Bitrix\Catalog\PriceTable::getList(
array(
"filter" => array(
"=PRODUCT_ID" => $PRODUCT_ID,
),
)
);
while ($arFields = $res->fetch())
{
$result = \Bitrix\Catalog\Model\Price::delete($arFields["ID"]);
$result->__destruct();
// Warning. Потому что произошла ошибка, и не сделали $result->isSuccess(), $result->getErrors(), $result->getErrorMessages()
}
}
Деструктор Bitrix\Main\ORM\Data\Result выкидывает Warning, если вернулась ошибка, и мы забыли сделать $result->isSuccess(), $result->getErrors() или $result->getErrorMessages()
Не забывайте проверять результат. Проблема не в том месте, где мы выкидываем ошибку. А в том месте, где мы не проверяем ошибку Bitrix\Main\ORM\Data\Result->__destruct( )
Так не будет Warning:
$result = \Bitrix\Catalog\Model\Price::delete( $arFields["ID"] );
if (!$result->isSuccess())
{
// нужна проверка isSuccess, чтобы не было Warning
// https://dev.1c-bitrix.ru/community/webdev/user/25773/blog/45090/
//echo "Ошибка";
//echo "<pre>"; print_r( $result->getErrors() ) ;echo "</pre>";
//echo "<pre>"; print_r( $result->getErrorMessages() ) ;echo "</pre>";
}
$result->__destruct();
В документации эта ситуация упоминается, но считается редкой:
В предыдущих примерах есть нюанс: запрос на обновление данных вызывается без проверки результата. Если запрос не прошел из-за "проваленной" валидации, и не была вызвана проверка isSuccess(), система сгенерирует E_USER_WARNING со списком ошибок, который можно будет увидеть в логе сайта (если соответствующим образом настроить .settings.php).
Самое плохое, если Warning появляется при обмене с 1С, или при самодельном импорте/экспорте. В таких ситуациях, где мы не можем исправить чужой скрипт вывод, вывод предупреждений на сайте надо отключить.
Битрикс больше не вызывает метод ShowTaskForm из действий (активити) бизнес-процессов на странице выполнения задания. Последняя версия, где работало 24.200.0. Раньше мы могли скопировать активити и сделать своё кастомное действие с формой.
В форме мы могли рисовать свои собственные поля, в том числе таблицы полей. Могли делать вычисления одних полей из других полей и т. п.
В приложении картинка, как выглядело для пользователя Продление командировки, чтобы он заполнил форму прямо в задании.
Последняя версия, в которой работало:
Бизнес-процессы (bizproc) 24.200.0 от 10.04.2024
Далее от bizproc 24.200.0 зависят модули, которые тоже нельзя обновлять выше версий:
Дизайнер бизнес-процессов (bizprocdesigner) 24.600.0 от 28.10.2024
Мобильные бизнес-процессы (bizprocmobile) 24.200.0 от 10.04.2024
CRM (crm) 24.1000.0 от 01.11.2024
Теперь Битрикс предлагает свои активити (запрос дополнительной информации и запрос дополнительной информации с отклонением). Формы активити содержат типовые поля переменных бизнес-процесса, но влезть туда со своим кодом нельзя.
Есть вариант добавить форму, если исправить шаблоны компонентов Битрикс, или с помощью javascript что-то дорисовать. Но это только до следующего обновления, потом придётся восстанавливать.
Тестовый бизнес-процесс:
На новых версиях единственный способ более-менее стандартный, но ужасно некрасивый - в описании задания просить пользователя перейти по ссылке, где-то в другом месте заполнить нашу форму.
Пример текста задания для активити «Утверждение документа»:
Наш документ: {=System:HostUrl}{{=getdocumenturl()}}
1. Перейдите по ссылке и заполните форму для дополнительных сведений к документу:
{=System:HostUrl}/askaron/test.php?ELEMENT_ID={{ID элемента}}&WORKFLOW_ID={=Workflow:ID}
2. После заполнения формы нажмите «Утвердить дополнительные сведения к документу» в этой форме.
На своей странице /askaron/test.php мы рисуем свою форму, которая что-то куда-то сохраняет. Потом в бизнес-процессе мы должны эту информацию прочитать.
В приложении картинки тестового процесса, как можно сделать по-новому.
Для выполнения каких-либо действий в назначенный момент в Битриксе используются агенты: учебный курс и cправка API.
Агенты названы крайне неудачно "периодические" и "непериодические". Разберём, какие реально бывают агенты.
Агент - это запись в специальной таблице:
какой код надо выполнить,
когда выполнить,
с каким периодом выполнять,
каким способом назначать время следующего запуска агента (периодический или непериодический агент).
Обычно, когда пользователь зашел на страничку сайта, ядро Битрикса смотрит, есть ли агенты, время которых наступило и выполняет их.
Важно. В начале хита еще не объявлена переменная $USER. Её в агентах использовать нельзя.
Можно в агенте создать объект $USER, что-то с ним сделать и уничтожить.
Реальное время запуска агента обычно чуть-чуть позже, чем время, на которое назначен агент. Момент запуска — это когда кто-то зашел на страницу сайта.
Настройки -> Настройки продукта -> Агенты:
Агенты, прежде всего, бывают повторяющиеся или неповторяющиеся. Это зависит от программиста, который написал код агента.
Если функция агента возвращает вызов себя, то агент повторяется.
Если функция агента ничего не возвращает, то агент будет удален из таблицы и больше не запустится. Агент не повторяется.
Программист может сделать агента, который повторится бесконечное число раз. Или только 2-3 раза в зависимости от условий. В списке агентов это увидеть нельзя. Только смотреть в код.
Пример функций агентов повторяющихся бесконечное число раз:
// пример функций агентов
function TestAgentPeriod()
{
AddMessage2Log( "Периодический BX_CRONTAB:".BX_CRONTAB." BX_CRONTAB_SUPPORT:".BX_CRONTAB_SUPPORT );
return "TestAgentPeriod();";
}
function TestAgentNotPeriod()
{
AddMessage2Log( "Непериодический BX_CRONTAB:".BX_CRONTAB." BX_CRONTAB_SUPPORT:".BX_CRONTAB_SUPPORT );
return "TestAgentNotPeriod();";
}
Вычисление следующего времени запуска.
Для повторяющихся агентов есть смыл говорить об интервале запуска и способе вычисления времени следующего запуска.
В данном примере интервал агентов 15 секунд. Один агент периодический, а другой непериодический.
Назначенное время следующего запуска периодического агента вычисляется так:
Старое назначенное время агента + интервал.
Этот способ позволяет запустить агент точное число раз. Например, раз в день запускается агент очистки старых почтовых событий или агент с ежедневным отчетом о посещаемости сайта.
Назначенное время следующего запуска непериодического агента вычисляется так:
Время завершения последнего запуска агента (выполнение return агента) + интервал
Абсолютное большинство агентов непериодические.
Например, агент пересчета рейтингов запускается раз в час. Но если за сутки не было ни одного посетителя, то логичнее выполнить агент один раз и сдвинуть назначенное время следующего запуска на час вперед после запуска. В случае периодического агента, этот код выполнился бы 24 раза за все сутки.
Агенты могут запускаться не только на хитах пользователя, но и на кроне. Но, как это правильно настроить, — тема отдельной большой статьи.
Примерная команда для создания символической ссылки local на другую папку, в вашем случае может быть другой путь.
# путь может отличаться на сервере
# не запускать из под root, лучше под своим пользователем.
# !! сайт битрикса добавил в путь пробел.
#ln -s ../. ./www/local local
Мы делали общую папку local, раздельные папки local. Пришли к решению:
- при добавлении нового сайта на разных доменах всегда делать общую папку local, вместе с bitrix и upload - с разными папками local админка работает по-разному, в зависимости от домена под которым зашли - разные $_SERVER["DOCUMENT_ROOT"] и разные local, - делать общую папку /local, чтобы в админке были списки шаблонов сайта, и Битрикс ничего не ломал при сохранении настроек сайта, чтобы срабатывали все обработчики событий в админке и подключались все модули.
Фактически, при добавлении второго сайта приходится дорабатывать первый сайт, чтобы он поддерживал многосайтовость. Это можно включать в оценку работ по дополнительному сайту.
- обработчики будут вызываться на всех сайтах. Надо делать проверки внутри обработчиков для каких сайтов обработчики. Например, Обработчики для авторизации по телефону должны иметь настройки для каких сайтов. - обработчики можно указывать для одного из сайтов в /local/php_interface/s1/init.php, где s1 - id сайта , но в админке этот обработчик из /s1/init/php не вызовется - свои модули дорабатывать, чтобы поддерживали многосайтовость, если мешают работать одному из сайтов. - доработка модуля из маркетплейса, если не наш, - поменять версию с 1.1.0 на 1001.1.0, чтобы не обновлялся. Поменять название и описание, что модуль изменён и что в нём изменено. В будущем самостоятельно следить за модулем и его обновлениями, - шаблоны и классы, если они относятся только к одному сайту назвать с именем сайта в папке local. - шаблоны компонентов или сайтов с одинаковым именем переименовывать. Избегать имён шаблонов компонентов .default в шаблоне сайта .default - обработчики связанные с почтовыми шаблонами должны понимать для какого сайта обрабатывается письмо
Общая папка local избавляет от кучи проблем. Правда, создаются новые проблемы. Непонятно, к какому из двух сайтов относится общий код - желательно комментировать или переименовать. Но это лучше, чем неправильно работающая админка.
Уже существует большое количество готовых типов дополнительных пользовательских полей.
В том числе есть такие поля, которые не поддерживаются другими подобными модулями с самодельными настройками: - многострочное поле ввода, которое может превысить 2000 символов. - файл
Вопросов возникнуть не должно, как добавить новую настройку, — это стандартный функционал Битрикса. Аналогичные пользовательские поля есть у пользователя и у разделов инфоблока.
Постоев Олег, очень много раз приходилось пользоваться подобными собственными решениями с костылями. А тут все типы свойств основные. Вообще здорово. Как понадобится такой функционал, сразу вспомните о модуле
А мне непонятно, почему нельзя было ограничиться просто просмотром и редактированием в админке и надо было доработать так, чтобы запрещать использовать затем стандартный COption::SetOptionString.
Также не отображаются раннее введённые значения. Т.е. обязательно создать в вашем модуле их?
Максимов Андрей, модуль хранит настройки в отдельной таблице - для Пользовательских полей, а не в таблице опций Битрикса. Метод COption::GetOptionString переопределить можно. Метод COption::SetOptionString переопределить нельзя и он будет работать неправильно. В документации и в описании к модулю написано, чтобы вы не использовали COption::SetOptionString, а использовали правильный метод.
Было бы не плохо иметь возможность, запрещать изменять значения определенных св-ств, столкнулись с ситуацией что после обмена, из св-ва тип файл множественное, затираются картинки, загруженные через админку.
Мы рассмотрели, какие бывают агенты. Теперь научимся их запускать на кроне. Мы сможем переложить часть задач с пользователей сайта на крон и ускорить время выполнения страниц.
Признаюсь. К этому снаряду я подходил несколько раз. И только с последнего толчка смог осилить этот вес. Сложность в том, что существует большое количество недокументированных констант и опций. Их совместное поведение совершенно не очевидно.
Константы, которые могут влиять на запуск агентов и отправку писем:
BX_CRONTAB
BX_CRONTAB_SUPPORT
NO_AGENT_CHECK
DisableEventsCheck
Опции модуля main, которые влияют на запуск агентов:
agents_use_crontab - по умолчанию не задана
check_agents - по умолчанию не задана
При этом не всё можно прочитать в исходном коде. Файл ядра Битрикса /bitrix/modules/main/include.php обфусцирован.
Нам надо повесить все агенты на крон.
Была подобная статья и учебный курс, но там есть фатальный недостаток: все почтовые события тоже вешаются на крон. Крон работает с минимальной частотой раз в минуту. Получается, что пользователь нажимает «восстановить пароль» и минуту ждет письмо. Еще один недостаток — статья устарела и в ней нет, как настроить резервное копирование по расписанию.
Нам надо, чтобы отправка писем была на хитах, а все агенты и резервное копирование работали на кроне.
Посмотрим, как сейчас обстоят дела в Битриксе:
По умолчанию на кроне вызывается файл /bitrix/modules/main/tools/cron_events.php:
В файле в самом начале стоит define("BX_CRONTAB", true);. Из-за этого в прологе устанавливается другая константа define("BX_CRONTAB_SUPPORT", true);. В результате данный крон-скрипт обрабатывает ТОЛЬКО непериодические агенты.
Исходный код функции обработки агентов.
function CheckAgents()
{
...
//For a while agents will execute only on primary cluster group
if((defined("NO_AGENT_CHECK") && NO_AGENT_CHECK===true) || (defined("BX_CLUSTER_GROUP") && BX_CLUSTER_GROUP !== 1))
return null;
$agents_use_crontab = COption::GetOptionString("main", "agents_use_crontab", "N");
$str_crontab = "";
if($agents_use_crontab=="Y" || (defined("BX_CRONTAB_SUPPORT") && BX_CRONTAB_SUPPORT===true))
{
if(defined("BX_CRONTAB") && BX_CRONTAB===true)
$str_crontab = " AND IS_PERIOD='N' ";
else
$str_crontab = " AND IS_PERIOD='Y' ";
}
...
return CAgent::ExecuteAgents($str_crontab);
}
Настройка агентов на кроне:
Проверьте, чтобы в файле dbconn.php не было установленных констант:
BX_CRONTAB
BX_CRONTAB_SUPPORT
NO_AGENT_CHECK
DisableEventsCheck
Установите опцию, которая запрещает выполнение агента в прологе:
COption::SetOptionString("main", "check_agents", "N");
echo COption::GetOptionString("main", "check_agents", "Y"); // должно вывестись N
Опция, которая влияет на выбор агентов в функции CheckAgents, должна быть не определена или "N".
COption::SetOptionString("main", "agents_use_crontab", "N");
echo COption::GetOptionString("main", "agents_use_crontab", "N"); // должно вывестись N
<?php
$_SERVER["DOCUMENT_ROOT"] = realpath(dirname(__FILE__)."/. ./..");
$DOCUMENT_ROOT = $_SERVER["DOCUMENT_ROOT"];
define("NO_KEEP_STATISTIC", true);
define("NOT_CHECK_PERMISSIONS",true);
define('BX_NO_ACCELERATOR_RESET', true); // чтобы не глючило на VMBitrix 3.1 из-за Zend при отправке бэкапа в облако.
// здесь никакой агент не выполнится. Потому что мы сделали COption::SetOptionString("main", "check_agents", "N");
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");
@set_time_limit(0);
@ignore_user_abort(true);
CAgent::CheckAgents(); // а вот тут все агенты выполнятся. И периодические, и непериодические
CEvent::CheckEvents(); // почтовые события мы оставили выполняться на хитах. Но и тут они могут выполняться. Почему нет?
define("BX_CRONTAB", true);
// модуль email-маркетинг
if(CModule::IncludeModule('sender'))
{
\Bitrix\Sender\MailingManager::checkPeriod(false);
\Bitrix\Sender\MailingManager::checkSend();
}
// а еще есть файлик резервного копирования, который запустится, когда его время придет.
require($_SERVER['DOCUMENT_ROOT']."/bitrix/modules/main/tools/backup.php");
?>
Пропишите правило в крон, например * * * * * /usr/bin/php -f /home/bitrix/www/bitrix/php_interface/cron_events.php
Результат
Теперь должно работать. Все агенты периодические и непериодические запускаются на cron. Все почтовые события отправляются на хитах пользователей сразу. Если к отправке письма привязана отправка SMS, то SMS тоже отправится сразу и не будет ждать крона.
Недостатки
Решение вполне рабочее, но есть проблемы:
1. Свой файл /bitrix/php_interface/cron_events.php, как и в старой статье, не будет обновляться.
Битрикс уже добавлял в крон резервное копирование по расписанию. Если они еще что-то добавят, то у вас не появится новый функционал.
2. В Виртуальной машине Битрикса уже настроен крон для файла /bitrix/modules/main/tools/cron_events.php. Вам придется настроить крон на свой файл /bitrix/php_interface/cron_events.php
Решение
Мы написали свой модуль «Агенты на кроне», который очень прост, удобен и лишен этих недостатков.
terseto, установите модуль на тестовый сайт https://labs.1c-bitrix.ru/ а потом скопируйте /bitrix/modules/askaron.agents к себе. Модуль бесплатный. DisableEventsCheck не трогайте, она отключает отправку писем.
Потом установите define("BX_CRONTAB_SUPPORT", true); в dbconn.php
Битрикс рекомендует для ускорения работы сайта переносить выполнение агентов с хитов пользователей на крон.
Агенты — это служебные задачи, которые запускаются в определенное время. Например, пересчет рейтинга пользователей сайта запускается раз в час.
Агенты запускаются, когда какой-нибудь пользователь заходит на сайт. Если при посещении страницы вдруг запустился пересчет рейтингов, то страница может дольше открываться.
Разумно запускать выполнение агентов с помощью служебной программы cron, а не на хитах пользователей.
В Битриксе нет понятного инструмента для переноса агентов на крон.
Есть несколько советов и моя статья, как создать отдельный файл, как настроить крон и установить несколько непонятных констант.
Такие решения рабочие, но требуют настройки, изучения, и свой отдельный крон-файл не будет обновляться.
Мы используем стандартный файл Битрикса /bitrix/modules/main/tools/cron_events.php. Крон уже настроен в Виртуальной машине Битрикса для этого файла, и делать ничего не надо.
На других хостингах вам придется настроить правило, например: * * * * * /usr/bin/php -f /home/bitrix/www/bitrix/modules/main/tools/cron_events.php
Об этом написано в подсказке на странице настроек:
С модулем «Агенты на кроне» будут все возможности, которые появятся в Битриксе при будущих обновлениях.
Мы очень старались сделать модуль простым и понятным. Поэтому он немножко платный. Срок демо-периода 30 дней. Демо-версия полностью функциональная.
Модуль бесплатный.
UPD 25.11.2014 Частые вопросы:
— Нужно ли прописывать константу BX_CRONTAB_SUPPORT в dbconn.php?
— Нет, необязательно. С нашим модулем агенты не зависят от константы BX_CRONTAB_SUPPORT.
Но от этой константы в Битриксе зависит отправка почты.
Если вы напишите define("BX_CRONTAB_SUPPORT", true) ; в dbconn.php, то почтовые события будут срабатывать на кроне раз в минуту.
Если уберете константу, то почта будет отправляться без задержки на хитах пользователей.
— Нужно ли прописывать константу BX_CRONTAB в dbconn.php?
— Нет, ни в коем случае, забудьте про неё. Константа BX_CRONTAB уже прописана в служебном файле, который вызывается кроном. В dbconn.php для всех страниц её включать нельзя.
Дмитрий, важнейшее преимущество модуля, кроме простоты настроек в том, что вместе с агентами на крон не переносятся почтовые сообщения. Очень бесит, когда письма о заказе приходится ждать минуту.
Модуль не будет трогать вашу почту. С модулем вы сами решаете переносить почту на агенты или нет с помощью константы BX_CRONTAB_SUPPORT
Зайцев Артемий, я только за упрощение, просто в данном случае просто не понятно что именно упрощается. Наскоком на одном из проектов я установил модуль, но возникла проблема с пингами в задачах (наверное вы в курсе, пишут об этом в отзывах) и получается прежде чем упрощать все равно приходится разбираться в том какие действия выполняет модуль, и что упрощается). Иными словами - чтобы это упрощение вкусить - нужно понять что мне нужно делать и что не нужно.
Пока что правильно я вас понял - суть упрощения в том что "не нужно настраивать в ядре Б24 опции связанные с запуском агентов - их делает сам модуль", но при этом крон настраивать нужно?
Т.е конкретно из стандартного мануала вычеркиваем пункты
Дмитрий, что касается неправильной работы каких-то отдельных агентов - надо обращаться в разработчику агентов, то есть к Битриксу, если это модуль задач. Битрикс обычно просит удалить наш модуль и настроить стандартным способом. Регламент технической поддержки не позволяет, что-либо проверять, если есть сторонние модули.
Группы на сайте создаются не только сотрудниками «1С-Битрикс», но и партнерами компании. Поэтому мнения участников групп могут не совпадать с позицией компании «1С-Битрикс».