Рано или поздно любой веб-проект обрастает задачами, которые нужно выполнять регулярно: рассылки, очистка кэша, синхронизация данных. И тут на сцену выходит cron. В Yii есть удобные инструменты, чтобы не превратить это в хаос. Давай разберёмся, как настроить планировщик и не сойти с ума.

Digital-студия WNDER

Почему cron — это не страшно, а удобно

Cron — это демон в Unix-подобных системах, который запускает команды по расписанию. В Yii есть консольные команды, которые идеально подходят для таких задач. Вместо того чтобы писать костыли на PHP, ты просто создаёшь контроллер для консоли и указываешь его в crontab.

Представь: каждый день в 3 часа ночи нужно чистить логи. Ты можешь, конечно, делать это вручную, но лучше поручить крону. Yii предоставляет удобный интерфейс для консольных команд — yii\console\Controller.

Вот пример простой команды, которая удаляет старые логи:

<?php
namespace app\commands;

use yii\console\Controller;
use Yii;
use yii\helpers\FileHelper;

class LogController extends Controller
{
    public function actionClean()
    {
        $logPath = Yii::getAlias('@runtime/logs');
        $files = FileHelper::findFiles($logPath, ['only' => ['*.log']]);
        foreach ($files as $file) {
            if (filemtime($file) < time() - 7 * 24 * 3600) {
                unlink($file);
            }
        }
        echo "Старые логи удалены.\n";
    }
}

Теперь достаточно добавить в crontab строку:

0 3 * * * /usr/bin/php /path/to/yii log/clean

И всё, задача работает без твоего участия.

Планировщик задач в Yii: зачем он нужен, если есть cron

Cron — штука мощная, но не всегда удобная. Например, если нужно запускать задачу каждые 5 минут, а сервер перегружен, или если ты хочешь управлять расписанием из админки. Тут на помощь приходит планировщик задач — компонент, который сам решает, когда что запускать.

В Yii нет встроенного планировщика, но его легко сделать самому. Идея проста: создаём команду, которая запускается каждую минуту через cron, а внутри проверяет, какие задачи пора выполнить. Для этого можно использовать таблицу в базе данных с расписанием.

Пример миграции для таблицы задач:

<?php
use yii\db\Migration;

class m250101_000000_create_scheduler_table extends Migration
{
    public function up()
    {
        $this->createTable('{{%scheduler_task}}', [
            'id' => $this->primaryKey(),
            'name' => $this->string()->notNull(),
            'command' => $this->string()->notNull(),
            'interval' => $this->integer()->notNull(), // в секундах
            'last_run' => $this->integer()->null(),
            'is_active' => $this->boolean()->defaultValue(true),
        ]);
    }

    public function down()
    {
        $this->dropTable('{{%scheduler_task}}');
    }
}

Теперь создадим консольную команду, которая будет проверять задачи и запускать те, чьё время пришло:

<?php
namespace app\commands;

use yii\console\Controller;
use app\models\SchedulerTask;
use Yii;

class SchedulerController extends Controller
{
    public function actionRun()
    {
        $tasks = SchedulerTask::find()->where(['is_active' => true])->all();
        foreach ($tasks as $task) {
            if ($task->last_run === null || (time() - $task->last_run) >= $task->interval) {
                $command = $task->command;
                Yii::$app->run($command);
                $task->last_run = time();
                $task->save(false);
            }
        }
    }
}

И добавляем в crontab запуск каждую минуту:

* * * * * /usr/bin/php /path/to/yii scheduler/run

Теперь ты можешь управлять расписанием через базу данных или админку.

Правило: Всегда логируйте выполнение фоновых задач. Даже если задача отработала успешно, запись в логе поможет отловить странные баги, когда что-то пошло не так.

Как избежать типичных грабель

Работа с кроном и планировщиком полна подводных камней. Вот несколько советов, которые сэкономят тебе нервы.

  • Не запускайте тяжёлые задачи каждую минуту. Если задача выполняется дольше минуты, cron может запустить её повторно, пока предыдущая ещё не завершилась. Используйте блокировки (например, через файл или мьютекс).
  • Указывайте полные пути. В crontab окружение может отличаться от твоего терминала, поэтому используйте абсолютные пути к PHP и к файлу yii.
  • Проверяйте права. Убедитесь, что пользователь, от имени которого работает cron, имеет доступ к файлам и базе данных.
  • Используйте try-catch. Ошибка в одной задаче не должна ронять весь планировщик.

Вот пример блокировки через файл:

public function actionRun()
{
    $lockFile = Yii::getAlias('@runtime/scheduler.lock');
    if (file_exists($lockFile)) {
        echo "Планировщик уже запущен.\n";
        return;
    }
    file_put_contents($lockFile, getmypid());
    try {
        // ... логика
    } finally {
        unlink($lockFile);
    }
}

Сравнение подходов: cron vs планировщик

Что выбрать? Зависит от задачи. Вот таблица, которая поможет определиться.

Критерий Cron Планировщик в Yii
Простота настройки Высокая Средняя
Гибкость расписания Ограничена Высокая
Управление из админки Нет Да
Зависимость от ОС Unix-подобные Любая

Если у тебя простые задачи и ты не хочешь городить огород — cron. Если нужен контроль и гибкость — планировщик.

Практический пример: рассылка писем

Допустим, у нас есть задача — каждую ночь отправлять письма пользователям. Создадим команду, которая выбирает пользователей и ставит письма в очередь.

<?php
namespace app\commands;

use yii\console\Controller;
use app\models\User;
use Yii;

class NewsletterController extends Controller
{
    public function actionSend()
    {
        $users = User::find()->where(['is_subscribed' => true])->all();
        foreach ($users as $user) {
            Yii::$app->mailer->compose()
                ->setTo($user->email)
                ->setSubject('Новости')
                ->setTextBody('Привет!')
                ->send();
        }
        echo "Рассылка завершена.\n";
    }
}

Добавляем в crontab:

0 2 * * * /usr/bin/php /path/to/yii newsletter/send

Всё, письма уходят каждую ночь.

Лайфхак: Если рассылка большая, разбей её на части. Например, отправляй по 100 писем за раз, а остальные — в следующем запуске. Иначе можешь получить таймаут или блокировку от почтового сервиса.

Что в итоге

Cron и планировщик в Yii — это мощные инструменты для автоматизации. Главное — не бояться экспериментировать и всегда помнить о безопасности и логировании. Начни с простых задач, а потом усложняй. И не забудь про блокировки, чтобы избежать наложения задач.

Если хочешь, чтобы всё работало как часы, следуй правилам: используй консольные команды, проверяй расписание, логируй и тестируй. Тогда фоновые задачи станут твоими незаметными помощниками.

Студия WNDER