Yii2-команда работает вручную, но не запускается из cron

Ситуация знакомая: команда Yii2 отлично запускается вручную по SSH, но из cron ничего не происходит. В коде ошибок нет, в браузере сайт работает, а фоновые задачи молчат. Чаще всего причина не в самой команде, а в окружении cron: другая рабочая директория, другая версия PHP, пустой PATH, нет переменных окружения или вывод никуда не записывается.

Проверить команду вручную

Сначала нужно запустить команду из директории проекта тем же пользователем, от которого работает cron.

cd /var/www/site.ru
php yii sitemap/generate

Если вручную команда падает, cron ни при чём. Сначала нужно исправить саму ошибку. Если вручную работает, переходим к окружению cron.

Полный путь к PHP

В cron не стоит полагаться на php из PATH. Там может быть другая версия или PHP может вообще не находиться.

which php
php -v

В crontab лучше писать полный путь:

* * * * * cd /var/www/site.ru && /usr/bin/php yii queue/run >> runtime/logs/cron.log 2>&1

Если на сервере несколько версий PHP, путь может быть /usr/bin/php8.2, php82 или другим. Его нужно проверить на конкретном сервере.

Рабочая директория

Yii2-команда часто зависит от относительных путей. Если cron запускает её не из корня проекта, приложение может не найти конфиги, runtime или файлы.

Плохой вариант:

* * * * * /usr/bin/php /var/www/site.ru/yii queue/run

Он может работать, но при относительных путях лучше явно перейти в проект:

* * * * * cd /var/www/site.ru && /usr/bin/php yii queue/run

Логирование вывода

Если cron не пишет лог, диагностика почти слепая. Нужно перенаправить stdout и stderr в файл.

* * * * * cd /var/www/site.ru && /usr/bin/php yii command/name >> runtime/logs/cron.log 2>&1

После этого можно посмотреть, что реально происходит:

tail -n 100 runtime/logs/cron.log

Иногда сразу видно: permission denied, class not found, wrong PHP version, could not open input file.

Переменные окружения

Если проект использует .env или переменные окружения, в cron они могут отсутствовать. В SSH-сессии переменная есть, а в cron — нет.

* * * * * printenv > /tmp/cron-env.txt

Для Yii2 лучше явно загружать .env в bootstrap приложения или передавать нужные переменные в crontab. Главное — не хранить секреты в открытом месте без контроля доступа.

Права пользователя

Cron может запускаться от другого пользователя, у которого нет прав на runtime, uploads или нужные файлы.

whoami
ls -la runtime
ls -la runtime/logs

Если лог не создаётся, нужно проверить права на runtime/logs. Команда может выполняться, но не иметь возможности записать результат.

Абсолютные пути в команде

Если команда работает с файлами, лучше использовать aliases Yii2 или абсолютные пути. Относительный путь может вести не туда.

$path = Yii::getAlias('@runtime') . '/exports/report.csv';

Это надёжнее, чем просто exports/report.csv, особенно в cron.

Параллельный запуск

Если команда запускается каждую минуту, а выполняется пять минут, она может стартовать несколько раз параллельно. Это приводит к блокировкам и дублям.

$mutex = Yii::$app->mutex;

if (!$mutex->acquire('cron-command-name', 0)) {
    return;
}

try {
    // выполнение команды
} finally {
    $mutex->release('cron-command-name');
}

Проверить системный cron log

На некоторых серверах можно посмотреть, запускал ли cron задачу вообще.

grep CRON /var/log/syslog
grep CRON /var/log/cron

На shared-хостинге такой доступ может быть закрыт, поэтому особенно важно писать собственный лог команды.

Чек-лист диагностики

  1. Запустить команду вручную из корня проекта.
  2. Проверить пользователя, от которого работает cron.
  3. Указать полный путь к PHP.
  4. Явно перейти в директорию проекта через cd.
  5. Записать stdout и stderr в лог.
  6. Проверить переменные окружения.
  7. Проверить права на runtime и logs.
  8. Добавить mutex, если команда не должна запускаться параллельно.

Если команда работает вручную, но не работает в cron, почти всегда различается окружение. Поэтому диагностика должна сравнить не код, а условия запуска: путь, пользователь, PHP, env, директория и права.

Комментарии (0)

Пока нет комментариев. Будьте первым!