Backend

Очереди в Laravel: Redis Queue, Horizon и Supervisor

Никита Литвяков
Никита Литвяков
Senior PHP / Laravel Backend Developer
Обложка статьи: Очереди

Не всё, что делает приложение, должно происходить во время HTTP-запроса. Отправка email, генерация PDF, дёрганье внешнего API, рассылка пуш-уведомлений — это секунды и минуты. Заставлять пользователя ждать ответа всё это время — плохая идея.

Зачем нужны очереди

Очередь — это «отложенная работа». Контроллер кладёт задачу в очередь и сразу возвращает ответ пользователю. Отдельный процесс-воркер забирает задачу и выполняет её в фоне.

Что это даёт:

  • Быстрые ответы. HTTP-запрос завершился за 50 мс, а тяжёлая работа продолжается в фоне.
  • Устойчивость. Если внешний API упал — задача попробует выполниться позже.
  • Масштабирование. Воркеров можно запускать сколько нужно, независимо от веб-сервера.

Стек в Laravel

Redis — брокер. Хранит очередь задач. Быстрый, надёжный, хорошо подходит для большинства сценариев.

Laravel Horizon — дашборд и менеджер воркеров. Показывает throughput, провалившиеся задачи, время выполнения. Управляет тем, сколько процессов держать на каждой очереди.

Supervisor — системный демон Linux. Следит, чтобы процесс воркера всегда был запущен. Воркер упал — Supervisor поднял.

Связка простая: Supervisor запускает Horizon, Horizon управляет воркерами, воркеры читают задачи из Redis.

Простой job

class SendWelcomeEmail implements ShouldQueue
{
    use Queueable;

    public int $tries = 3;
    public int $backoff = 30;

    public function __construct(private int $userId) {}

    public function handle(Mailer $mailer): void
    {
        $user = User::findOrFail($this->userId);
        $mailer->to($user->email)->send(new WelcomeMail($user));
    }
}

// диспатч
SendWelcomeEmail::dispatch($user->id);

Заметьте: в job передаём id, а не саму модель. Между диспатчем и выполнением могут пройти минуты — за это время данные могут измениться.

Несколько очередей

Не сваливайте всё в одну очередь. Разные задачи — разная критичность и время выполнения.

SendSms::dispatch($payload)->onQueue('sms');
GenerateReport::dispatch($id)->onQueue('reports');

В Horizon настраивается отдельно: для sms — 10 воркеров и низкий timeout, для reports — 2 воркера с большим timeout.

Что обязательно учесть

  • Идемпотентность. Job может выполниться дважды (повторная попытка после таймаута). Код должен быть готов к этому.
  • Retry с backoff. Не долбить внешний API в цикле — давать паузу между попытками.
  • Failed jobs. Настройте мониторинг провалившихся задач, иначе они тихо умрут.
  • Перезапуск воркеров после деплоя. php artisan horizon:terminate — иначе старый код будет жить в памяти воркеров.

Запомнить

  • Очередь нужна для всего, что не обязано выполниться в HTTP-запросе.
  • Redis + Horizon + Supervisor — рабочая комбинация для большинства проектов.
  • Передавайте в job идентификаторы, а не модели.
  • Идемпотентность и retry — не опция, а требование.
#Laravel #Backend #Очереди
Поделиться:

Также может быть интересно