Каждый разработчик рано или поздно сталкивается с ситуацией, когда скрипт должен выполнить тяжёлую операцию: отправить письмо, обработать загрузку файла, сгенерировать отчёт. Если делать это сразу при запросе пользователя, страница будет грузиться вечность. Решение — очереди. Они позволяют отложить задачу и выполнить её в фоне. В этой статье я покажу, как организовать очереди в Yii2 с помощью Redis — быстро, надёжно и без боли.
Вы узнаете, как настроить компонент, как создавать и обрабатывать задачи, что делать с упавшими воркерами и как не потерять данные. В конце — несколько советов, которые сэкономят вам часы отладки.
Что такое очередь и зачем она нужна
Очередь — это список задач, которые нужно выполнить. Вы добавляете задачу в конец списка, а специальный обработчик (воркер) берёт её из начала и выполняет. Всё просто, как в обычной очереди в магазине: первый пришёл — первый ушёл.
В Yii2 очереди работают через специальное расширение yiisoft/yii2-queue. Оно поддерживает разные драйверы: файлы, базы данных, RabbitMQ и, конечно, Redis. Redis — это хранилище типа «ключ-значение», которое работает в памяти, поэтому оно очень быстрое. Идеально для очередей.
Зачем это нужно? Представьте, что пользователь нажимает кнопку «Отправить» на сайте. Если вы сразу отправляете 1000 писем, запрос будет выполняться несколько минут. Пользователь уйдёт, а письма так и не отправятся. С очередью вы просто кладёте задачу в Redis и мгновенно возвращаете ответ. Воркер, работающий в фоне, постепенно разберёт очередь и отправит все письма.
Установка и настройка Redis
Сначала убедитесь, что Redis установлен на сервере. Если нет — установите. На Ubuntu это делается одной командой:
sudo apt-get install redis-server
После установки запустите сервис и проверьте, что он работает:
redis-cli ping
Ответ должен быть PONG. Если да — всё отлично.
Теперь установите расширение для Yii2. Для этого в корне проекта выполните:
composer require yiisoft/yii2-queue
Затем настройте компонент в файле конфигурации. Обычно это config/console.php для консольных команд и config/web.php для веб-приложения. Добавьте в секцию components:
'components' => [
'queue' => [
'class' => \yii\queue\redis\Queue::class,
'redis' => 'redis', // компонент Redis
'channel' => 'my-queue', // имя канала очереди
'ttr' => 5 * 60, // время выполнения задачи (секунды)
'attempts' => 5, // количество попыток выполнить задачу
],
'redis' => [
'class' => \yii\redis\Connection::class,
'hostname' => 'localhost',
'port' => 6379,
'database' => 0,
],
],
Здесь queue — это компонент очереди, redis — подключение к Redis. Вы можете указать свой хост и порт, если Redis не на localhost.
Параметр ttr — время, которое воркер может выполнять задачу. Если задача выполняется дольше, она будет считаться зависшей и вернётся в очередь. attempts — сколько раз задача будет повторяться при ошибке.
Создание задачи и её обработка
Теперь создадим саму задачу. В Yii2 это делается через класс, который наследует yii\base\BaseObject и реализует интерфейс yii\queue\JobInterface. Внутри нужно определить метод execute($queue), где будет выполняться работа.
Допустим, нам нужно отправить письмо. Создадим класс SendEmailJob:
namespace app\jobs;
use yii\base\BaseObject;
use yii\queue\JobInterface;
use yii\queue\Queue;
class SendEmailJob extends BaseObject implements JobInterface
{
public $email;
public $subject;
public $body;
public function execute($queue)
{
// Здесь логика отправки письма
Yii::$app->mailer->compose()
->setTo($this->email)
->setSubject($this->subject)
->setTextBody($this->body)
->send();
}
}
Всё просто: мы описываем свойства, которые нужны для задачи, и в execute выполняем саму работу.
Чтобы добавить задачу в очередь, вызываем:
Yii::$app->queue->push(new SendEmailJob([
'email' => 'user@example.com',
'subject' => 'Привет!',
'body' => 'Это тестовое письмо.',
]));
Метод push добавляет задачу в очередь и возвращает её идентификатор. Вы можете сохранить этот ID, чтобы потом проверить статус задачи.
Теперь нужно запустить воркер, который будет обрабатывать задачи. Для этого в консоли выполните:
php yii queue/listen
Эта команда запускает воркер, который слушает очередь и выполняет задачи по мере их поступления. По умолчанию он работает бесконечно, пока вы его не остановите. Можно указать количество итераций или время работы через параметры.
Обработка ошибок и повторные попытки
Что делать, если задача упала? Например, почтовый сервер недоступен или данные оказались некорректными. Если просто выбросить исключение, задача будет помечена как неудачная и попадёт в список ошибок. Но часто бывает, что ошибка временная, и через минуту всё заработает.
В Yii2 есть встроенный механизм повторных попыток. Если в конфигурации указано attempts => 5, то при ошибке задача будет возвращена в очередь и попробована снова. Через 5 неудачных попыток она будет удалена и записана в журнал.
Вы также можете управлять повторной попыткой вручную. В методе execute можно вернуть специальный объект yii\queue\RetryableJobInterface, который позволяет указать, сколько раз повторять и с какой задержкой. Но для простоты используйте стандартные настройки.
Если вы хотите явно сообщить, что задача неудачная и повторять не надо, выбросьте исключение yii\queue\Exception или просто верните false.
Вот пример, как обработать ошибку и решить, повторять ли задачу:
public function execute($queue)
{
try {
$this->sendMail();
} catch (\Exception $e) {
// Логируем ошибку
Yii::error("Ошибка отправки письма: " . $e->getMessage());
// Возвращаем false, чтобы задача не повторялась
return false;
}
}
В этом случае задача будет считаться выполненной (даже с ошибкой) и не будет повторяться. Это удобно, когда повторять бесполезно.
Лайфхаки и советы
Теперь несколько практических советов, которые пригодятся в реальной работе.
Идемпотентность — это свойство операции, при котором повторное выполнение даёт тот же результат, что и первое. Например, отправка письма — не идемпотентна: если отправить дважды, пользователь получит два письма. Поэтому перед выполнением проверяйте, не была ли задача уже выполнена. Для этого можно хранить статус в базе данных.
Ещё один лайфхак: используйте несколько воркеров. Если задач много, один воркер может не справляться. Запустите несколько процессов:
php yii queue/listen &
php yii queue/listen &
php yii queue/listen &
Это ускорит обработку. Но не переусердствуйте: слишком много воркеров могут перегрузить Redis или базу данных.
Также следите за размером очереди. Если она растёт, а воркеры не справляются, значит, нужно либо добавить воркеров, либо оптимизировать задачи.
Вот небольшая таблица параметров очереди, которые стоит знать:
| Параметр | Описание | Пример значения |
|---|---|---|
channel |
Имя очереди. Позволяет разделять задачи по типам. | email-queue |
ttr |
Максимальное время выполнения задачи в секундах. | 300 |
attempts |
Количество попыток выполнения при ошибке. | 3 |
delay |
Задержка перед выполнением задачи (в секундах). | 60 |
Задержка delay задаётся при добавлении задачи. Например, если нужно отправить письмо через час, укажите delay => 3600.
Заключение
Очереди в Yii2 через Redis — это мощный инструмент, который позволяет разгрузить веб-приложение и сделать его отзывчивым. Мы разобрали, как настроить компонент, создать задачу, обработать ошибки и оптимизировать работу. Главное — не забывать про повторные попытки и идемпотентность.
Теперь вы можете смело внедрять очереди в свои проекты. Удачи!
Студия WNDER


