Автоматическая очистка кэша в 1С-Битрикс

Кэш ускоряет сайт, но на активных проектах — особенно с большим каталогом — папки bitrix/cache и bitrix/managed_cache могут разрастаться до десятков гигабайт. Ручная очистка из админки неудобна, поэтому обычно настраивают фоновый агент, который постепенно удаляет просроченные файлы кэша.

Ниже — рабочий способ для PHP 8+, проверенный на боевом сайте.


Как это устроено в Битрикс

Битрикс хранит файловый кэш в каталогах:

КаталогНазначение
/bitrix/cache/Основной файловый кэш компонентов
/bitrix/managed_cache/Управляемый кэш (меню, справочники и т.д.)
/bitrix/stack_cache/Стековый кэш
/bitrix/html_pages/HTML-кэш (композит)

В начале каждого .php-файла кэша записаны метки $datecreate и $dateexpire. Агент читает заголовок файла и удаляет только те записи, у которых срок жизни уже истёк.

Важно: агент не очищает весь кэш целиком. Живые (ещё не просроченные) файлы остаются — и это нормально. Если диск забивается из-за миллионов валидных записей, нужно дополнительно снижать CACHE_TIME в компонентах и ограничивать обход ботов.


Шаг 1. Функция очистки в init.php

Добавьте в /local/php_interface/init.php:

~/snippet
function clean_expire_cache($path = "")
{
    if (!class_exists("CFileCacheCleaner")) {
        require_once $_SERVER["DOCUMENT_ROOT"]
            . "/bitrix/modules/main/classes/general/cache_files_cleaner.php";
    }

    $currentTime = time();
    $endTime = (defined("BX_CRONTAB") && BX_CRONTAB === true)
        ? time() + 5   // на кроне — до 5 секунд за запуск
        : time() + 1;  // на хитах — не более 1 секунды

    // При возобновлении агент может передать полный путь — приводим к относительному
    if ($path !== "" && strpos($path, $_SERVER["DOCUMENT_ROOT"]) === 0) {
        $path = substr($path, strlen($_SERVER["DOCUMENT_ROOT"]));
    }

    $obCacheCleaner = new CFileCacheCleaner("all");

    if (!$obCacheCleaner->InitPath($path)) {
        return "clean_expire_cache();";
    }

    $obCacheCleaner->Start();
    $file = false;

    while ($file = $obCacheCleaner->GetNextFile()) {
        if (!is_string($file)) {
            continue;
        }

        $dateExpire = $obCacheCleaner->GetFileExpiration($file);

        if ($dateExpire && $dateExpire < $currentTime) {
            unlink($file);
        }

        if (time() >= $endTime) {
            break;
        }
    }

    // Сохраняем позицию для следующего запуска
    if (is_string($file)) {
        $resumePath = (strpos($file, $_SERVER["DOCUMENT_ROOT"]) === 0)
            ? substr($file, strlen($_SERVER["DOCUMENT_ROOT"]))
            : $file;

        return 'clean_expire_cache("' . str_replace('"', '\\"', $resumePath) . '");';
    }

    return "clean_expire_cache();";
}

Почему именно так (PHP 8+)

В старых примерах из документации часто встречается строка:

~/snippet
$curentTime = mktime(); // ❌ не работает в PHP 8+

В PHP 7 и ниже mktime() без аргументов возвращал текущий timestamp. В PHP 8.0+ вызов без параметров вызывает фатальную ошибку ArgumentCountError, и агент падает при каждом запуске, так и не удалив ни одного файла.

Используйте time() — это корректный и совместимый способ.

Второй типичный баг: при возобновлении в агент передаётся полный путь вида /home/user/www/bitrix/cache/..., а CFileCacheCleaner::InitPath() ожидает путь от корня сайта/bitrix/cache/.... Без нормализации агент сбрасывается в начало и ходит по кругу, не продвигаясь по каталогу.


Шаг 2. Регистрация агента

В админке: Настройки → Инструменты → Агенты → «Добавить агента».

ПолеЗначение
Модульmain
Функция агентаclean_expire_cache();
Интервал60 (секунд) или 300
АктивенДа

Либо программно (один раз):

~/snippet
CAgent::AddAgent(
    "clean_expire_cache();",
    "main",
    "N",       // не периодический — интервал от LAST_EXEC
    60,        // интервал в секундах
    "",
    "Y",       // активен
    ConvertTimeStamp(time(), "FULL")
);

Агент работает порциями: за один запуск обрабатывает файлы 1–5 секунд, запоминает позицию и продолжает со следующего вызова.

Обязательно: точка с запятой в имени агента

В поле «Функция агента» нужно писать именно clean_expire_cache(); — с ; в конце.

Битрикс выполняет агент через eval():

~/snippet
eval("\$eval_result=clean_expire_cache();");

Если в админке указать clean_expire_cache() без точки с запятой, получится невалидный PHP-код:

~/snippet
eval("\$eval_result=clean_expire_cache()"); // ❌ syntax error в PHP 8+

Агент падает с синтаксической ошибкой, остаётся в состоянии RUNNING = YLAST_EXEC не обновляется, RETRY_COUNT растёт — создаётся впечатление, что очистка «не работает».

Проверить имя в БД:

~/snippet
SELECT ID, NAME, RUNNING, LAST_EXEC, RETRY_COUNT
FROM b_agent
WHERE NAME LIKE 'clean_expire_cache%';

Исправить, если точка с запятой потерялась:

~/snippet
UPDATE b_agent
SET NAME = 'clean_expire_cache();', RUNNING = 'N', RETRY_COUNT = 0
WHERE NAME = 'clean_expire_cache()';

Шаг 3. Крон для агентов

Чтобы агенты запускались стабильно, а не только при заходах на сайт, настройте системный cron:

~/snippet
* * * * * bitrix test -f /home/bitrix/www/bitrix/modules/main/tools/cron_events.php && \
  /usr/bin/php -f /home/bitrix/www/bitrix/modules/main/tools/cron_events.php

Путь к сайту замените на свой. При запуске через cron в cron_events.php определяется константа BX_CRONTAB, и функция работает до 5 секунд за итерацию вместо 1.


Диагностика: агент «не помогает»

Если место на диске продолжает уменьшаться, проверьте агент в БД (b_agent) или в админке:

СимптомПричинаРешение
RUNNING = YLAST_EXEC пустой, RETRY_COUNT растётВ NAME агента нет ; в конце (clean_expire_cache() вместо clean_expire_cache();)Исправить имя, сбросить RUNNING = N
RUNNING = YLAST_EXEC пустой, ошибки в логеФатальная ошибка в функции (часто mktime() на PHP 8+)Исправить код, сбросить RUNNING = N
Кэш растёт, но файлы «свежие»Удаляются только просроченные записиСнизить CACHE_TIME, ограничить ботов
upload/ занимает больше, чем bitrix/cacheПроблема не в кэшеЧистить загрузки, резервные копии, логи

Сброс зависшего агента:

~/snippet
UPDATE b_agent
SET RUNNING = 'N', RETRY_COUNT = 0
WHERE NAME = 'clean_expire_cache();';

Проверка функции из CLI:

~/snippet
cd /home/bitrix/www
DOCUMENT_ROOT=/home/bitrix/www php -r "
\$_SERVER['DOCUMENT_ROOT'] = '/home/bitrix/www';
define('NO_KEEP_STATISTIC', true);
define('NOT_CHECK_PERMISSIONS', true);
define('BX_CRONTAB', true);
require 'bitrix/modules/main/include/prolog_before.php';
echo clean_expire_cache() . PHP_EOL;
"

Если видите ArgumentCountError: mktime() — код не адаптирован под PHP 8.


Что ещё можно сделать

  1. Снизить время кэширования в шаблонах компонентов каталога (CACHE_TIME — часто стоит 36000, то есть 10 часов).
  2. Ограничить ботов в robots.txt и на уровне веб-сервера — каждый уникальный URL создаёт новую запись кэша.
  3. Встроенная очистка Битрикс — при инвалидации кэша из админки или кода срабатывает Cache::delayedDelete() через очередь b_cache_clean_path. Это дополняет, но не заменяет агент по просрочке.
  4. Мониторинг размера — периодически смотрите du -sh bitrix/cache bitrix/managed_cache upload.

Итог

Автоматическая очистка просроченного кэша в Битрикс — стандартная практика: функция clean_expire_cache() + агент + cron. На PHP 8+ обязательно:

  • time() вместо mktime();
  • относительные пути /bitrix/cache/... при возобновлении агента;
  • clean_expire_cache(); с точкой с запятой в поле функции агента;
  • контроль зависшего агента в таблице b_agent.

Это не панацея от разросшегося каталога, но убирает «мёртвый» кэш без ручного вмешательства и предотвращает ситуацию, когда диск забивается файлами с истёкшим сроком жизни, которые никто не удаляет.

Рубрика:

Оставить комментарий

Ваш адрес эл. почты не будет опубликован. Обязательные поля помечены *