Здесь я бы хотел делиться со специалистами, выполняющими интеграцию нашей системы, некоторыми методами, помогающими нам в ежедневной работе выявлять ошибки как в нашей системе, так и в пользовательских скриптах. Последних, к счастью, намного больше .
Итак, начнем с агентов - как наилучшим образом диагностировать проблему, если она возникает в коде, который запускается с определенной периодичностью на
[spoiler]
Самый лучший пример - ошибка в шаблоне (или подключаемом в нем компоненте) генерации автоматической рассылки. Простая такая синтаксическая ошибка, обрывающая генерацию выпуска автоматической рассылки, а вместе с ней - агента и всей страницы, на которой агент имел несчастье выполниться.
Что это за агент?
Это
CPostingTemplate::Execute(); |
который создается с интервалом выполнения в 60 секунд, при наличии хотя бы одной активной автоматической рассылки.
Допустим, мы допустили синтаксическую ошибку в строке 66 компонента subscribe/subscr_news_my.php,
do { fh $news_counter++; |
подключаемого в шаблоне генерации автоматической рассылки:
<P>Добрый день!</P> <P><?$APPLICATION->IncludeFile("subscribe/subscr_news_my.php", Array( |
Что мы имеем в итоге?
На первом же запуске агента (вполне вероятно, что не на нашем хите, если сайт - рабочий) пользователь увидит два приветственных слова:
Добрый день |
После обновления страницы контент отображается отлично, но время следующего выполнения агента, несмотря на наши усилия, не сдвигается вперед, т.е. мы видим, что фактически агент не отрабатывает.
Что же делать, как нам добраться до причины ошибки?
Давайте посмотрим, что произошло после неуспешного запуска агента.
Находим в списке агентов наш
CPostingTemplate::Execute(); |
Выполняем SQL-запрос
select * from b_agent where ID=122 |
и видим, что, оказывается, у записи есть еще одно поле - DATE_CHECK (типа дата/время), и значение его, по странному стечению обстоятельств, ровно на 10 минут позже, чем момент последнего безуспешного выполнения агента.
Обратите внимание: значения LAST_EXEC и NEXT_EXEC не меняются, они "сдвинутся" только после успешного выполнения агента.
Итак, понятно, что DATE_CHECK означает момент следующей попытки запуска агента, но ждать каждый раз 10 минут - мягко говоря, неудобно.
Найдем соответствующую строку в ядре продукта
$strSql="UPDATE b_agent SET DATE_CHECK=DATE_ADD(IF(DATE_CHECK IS NULL, now(), DATE_CHECK), INTERVAL 600 SECOND) WHERE ID=".$db_result_agents_array["ID"]; |
в \bitrix\modules\main\classes\mysql\agent.php (рассмотрим на примере MySQL-версии), в объявлении CAgent::CheckAgents().
И после нее вставим код, переопределяющий $strSql, но только при обращении с нашего IP и только для "проблемного" агента:
if (($_SERVER["REMOTE_ADDR"] == "<X.X.X.X>") && ($db_result_agents_array["ID"] == <ID агента, в нашем примере - 122>)) { $strSql="UPDATE b_agent SET DATE_CHECK=DATE_ADD(IF(DATE_CHECK IS NULL, now(), DATE_CHECK), INTERVAL 1 SECOND) WHERE ID=".$db_result_agents_array["ID"]; } |
где <X.X.X.X> - ваш IP.
Обратите внимание, что реальный IP может фиксироваться в $_SERVER["HTTP_X_FORWARDED_FOR"], а не $_SERVER["REMOTE_ADDR"], в случае использования
Также для отключения механизма управляемого кеширования при работе с таблицей агентов используем:
define("CACHED_b_agent", false); |
в /bitrix/php_interface/dbconn.php
Теперь агент будет выполняться на каждом хите (если вы, конечно, не делаете больше одного хита в секунду).
Но ошибка, увы, все равно не отображается, хотя теперь на каждом своем хите мы видим белую страницу с надписью "Добрый день".
Какой же он, черт возьми, добрый!?
Всему виной - собачка. Не та, которая с ушками и хвостиком, а та, которая блокирует вывод ошибок.
Нашим разработчикам, конечно, виднее (честное слово, мы в техподдержке действительно так считаем! ), но собачки эти крови нашей попили вдоволь...
Впрочем, по порядку:
в CPostingTemplate::Execute() (\bitrix\modules\subscribe\classes\general\template.php):
CPostingTemplate::AddPosting($arRubric); |
в CPostingTemplate::AddPosting() (там же):
$arFields = @include($strFileName); |
Вот она, наша собачка...
Эту строку заменяем на:
if ($_SERVER["REMOTE_ADDR"] == "<X.X.X.X>") $arFields = include($strFileName); else $arFields = @include($strFileName); |
в результате:
Parse error: parse error, unexpected T_VARIABLE in ...subscribe\subscr_news_my.php on line 66 |
И теперь - не менее важный момент: не забудьте вернуть код ядра "на место" (если не хотите остаться без техподдержки из-за нарушения лицензионного соглашения ) и убрать отключение управляемого кеширования агентов в dbconn.php!
P.S. замечания действительно приветствуются - я прекрасно понимаю, что среди наших клиентов и партнеров есть люди, куда опытнее меня.
я порекомендую использовать запись в файл - до выполнения агента записывать значения: время, ид агента, имя. затем после выполнения результат.
также, для оракла все агенты выполняются в рамках одной транзакции, может и для mssql также.. но то, что если произойдет ошибка, к примеру на тридцатом агенте, то запросы обновления времени выполнения агента или его удаления не будут закоммичены
также, могу из опыта порекомендовать следующий способ отладки - создаем файл, копируем функцию проверки агентов, а также "проблемную" функцию в этот файл и префиксом "_" - и меняем как душе угодно, возвращать "на место" уже будет не нужно
Володя, а почему бы не создать также блог юмора ТП? С твоим владением пера и опытом тираж обеспечен