Иногда требуется периодически выполнять скрипт, время работы которого не укладывается в рамки серверных ограничений max_execution_time. Например, автоматический импорт больших списков или, как в моем примере, автоматический ресайз картинок инфоблока. В таких случаях требуется использовать пошаговый алгоритм.
Вот мой велосипед:
В данном примере скрипт раз в сутки проверяет наличие новых картинок и ресайзит их, но скрипт можно легко адаптировать и под другие задачи. Этот код можете использовать, если вы, так же как и я, любите использовать функцию ResizeImageGet для уменьшения картинок( http://dev.1c-bitrix.ru/api_help/main...ageget.php ).
Файл ImagesCronResize.php
<?
/*
*
* Скрипт автоматически кэширует все картинки в инфоблоке для ускорения загрузки страниц каталога
*
* */
class ImagesCronResize {
const MAX_EXECUTION_TIME = 40;
const AGENT_TIME_INTERVAL = 5; //минут
/*
* Агент ресайзит все превьюшки в инфоблоке под нужные размеры
*/
public static function resizeAgent($iLastId=0)
{
$startAgentTimestamp = time();
CModule::IncludeModule("iblock");
$arSelect = Array("ID", "NAME", "PREVIEW_PICTURE");
$arFilter = Array("IBLOCK_ID" => CATALOG_IBLOCK_ID, "ACTIVE" => "Y",">ID" => $iLastId );
$res = CIBlockElement::GetList(Array("ID"=>"ASC"), $arFilter, false, false, $arSelect);
while ($ob = $res->GetNextElement()) {
$arFields = $ob->GetFields();
if ($arFields['PREVIEW_PICTURE']>0) {
CFile::ResizeImageGet( $arFields['PREVIEW_PICTURE'], array('width'=>SMALL_PREVIEW_WIDTH, 'height'=>SMALL_PREVIEW_HEIGHT), BX_RESIZE_IMAGE_PROPORTIONAL, true); //BX_RESIZE_IMAGE_EXACT
CFile::ResizeImageGet( $arFields['PREVIEW_PICTURE'], array('width'=>BIG_PREVIEW_WIDTH, 'height'=>BIG_PREVIEW_HEIGHT), BX_RESIZE_IMAGE_PROPORTIONAL, true);
}
if ((time()-$startAgentTimestamp)>self::MAX_EXECUTION_TIME){
//Добавляем новый агент через 5 минут
self::addOneMoreStepAgent($arFields['ID']);
return false;
break;
}
}
return get_called_class()."::resizeAgent();";
}
public static function addAgent()
{
CAgent::AddAgent(
get_called_class()."::resizeAgent();", // имя функции
"", // идентификатор модуля
"N", // агент не критичен к кол-ву запусков
86400, // интервал запуска - 1 сутки
date("d.m.Y 05:00:00",strtotime("+1 day")),// дата первой проверки на запуск
"Y", // агент активен
date("d.m.Y 05:00:00",strtotime("+1 day")),// дата первого запуска
30);
}
protected function addOneMoreStepAgent($id)
{
CAgent::AddAgent(
get_called_class()."::resizeAgent(".intval($id).");", // имя функции
"", // идентификатор модуля
"N", // агент не критичен к кол-ву запусков
86400, // интервал запуска - 1 сутки
date("d.m.Y H:i:s",strtotime("+".self::AGENT_TIME_INTERVAL." minute")),// дата первой проверки на запуск
"Y", // агент активен
date("d.m.Y H:i:s",strtotime("+".self::AGENT_TIME_INTERVAL." minute")),// дата первого запуска
30);
}
}
?>
Лучше будет, если агенты будут работать на cron'e http://dev.1c-bitrix.ru/community/web...blog/2755/ Надеюсь кому-нибудь пригодится. Может кто посоветует, как улучшить алгортитм и расскажет о своих велосипедах.)
Насколько мне известно, битрикс кеширует результат ресайза. При последующих обращениях к файлу с заданными шириной и высотой через ResizeImageGet() будет возвращена уже отмасштабированная картинка. Если уж так жалко одного пользовательского хита по странице с вызовом ResizeImageGet(), то может это и имеет смысл, но я обычно не заморачиваюсь. Если бы ваш агент сохранял путь до отмасштабированного изображения куда-то, а вы уже обращались бы к этому пути, то да, возможно был бы какой-то смысл (ResizeImageGet не будет тратить время на CFile::GetFileArray()). Но мне кажется, если товар появился между запусками агента, то к нему за сутки уже произойдет пользовательский хит (если, конечно, товары сразу появляются в паблике после добавления), и тогда ваш агент выполнит ненужную работу.
Для многошаговых импортов не использую никогда агенты, предпочитаю контролировать выполнение шагов самостоятельно с помощью скрипта импорта.
Но агентам в свое время нашел множество других полезных применений. Например при добивании лида, если он оставил email на сайте, можно отправить несколько сообщений с его корзиной, если он не дошел до цели покупки, а может быть и дать скидку в одном из таких писем. Или, например, когда нужно очищать корзину конкретного покупателя спустя какое-то время (полчаса, скажем), если он не выкупил корзину.
Все верно Михаил. Функция ResizeImageGet кэширует результаты ресайза. У меня недавно был проект где выводилось сразу 30 карточек товара с предложениями и для каждого предложения от 3-5 превьюшек. Итого, в одном хите, при первом открытие какой-нибудь страницы, ресайзилось 150 картинок. Клиенту бы не понравилась такая скорость работы сайта после импорта товаров из 1с. Поэтому кэшировать картинки надо было заранее.
По-моему, пошаговость предпочтительней использовать для любых хостингов, не зависимо от возможности изменения настроек сервера. У меня, например, были скрипты импорта которые работали около 2 часов. Ставить max_execution_time 7200, как-то не очень изящно )
Цупко Игорь, я считаю, что так можно гибче управлять своим скриптом, отлаживать его Но, конечно, все зависит от конкретной задачи. Где-то имеет смысл прибегнуть к агентам, где-то - к ручному контролю
Вербовенко Федор, а) есть способы мониторить подвисшие скрипты б) вот как раз скрипты импорта, которые работают 2 часа нужно делать по крону, и этому процессу корректно выставлять пределы жрания памяти/процессора, чтобы они не мешали веб-серверу и другим процессам.
Группы на сайте создаются не только сотрудниками «1С-Битрикс», но и партнерами компании. Поэтому мнения участников групп могут не совпадать с позицией компании «1С-Битрикс».