Очереди в Laravel: когда пора перестать всё делать в запросе

Иногда один HTTP-запрос тащит за собой отправку писем, генерацию PDF, импорт из Excel и ещё пол-проекта. Пользователь ждёт, сервер задыхается. В этот момент самое время вынести тяжёлую работу в очереди.

Что уносить в очередь

Хорошее правило: всё, что не нужно для немедленного ответа пользователю, можно отправить в фон.

Обычно это: • массовая отправка email/SMS/уведомлений • генерация отчётов, PDF, архивов • импорты/экспорты (Excel, CSV, API) • синхронизация с внешними сервисами • тяжёлые расчёты и агрегации

Контроллер должен только принять данные, запустить нужные Jobs и вернуть быстрый ответ.

Базовый пример Job

Создадим задачу для генерации отчёта: php artisan make:job GenerateReport

Класс Job: php

namespace AppJobs;

use AppServicesReportService; use IlluminateBusQueueable; use IlluminateContractsQueueShouldQueue; use IlluminateFoundationBusDispatchable; use IlluminateQueueInteractsWithQueue; use IlluminateQueueSerializesModels;

class GenerateReport implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

public function __construct( public int $userId, ) {}

public function handle(ReportService $service): void { $service-generateForUser($this->userId); } }

Запуск из контроллера: GenerateReport::dispatch($user->id);

HTTP-ответ уходит сразу, а отчёт собирается в фоне.

Настройка воркера

В .env указываем драйвер очереди: QUEUE_CONNECTION=database

Создаём таблицу для задач и накатываем миграции: php artisan queue:table php artisan migrate

Запускаем воркер (дальше оборачиваем в systemd/supervisor): php artisan queue:work --tries=3

Этого уже достаточно, чтобы разгрузить большинство тяжёлых контроллеров.

Таймауты и повторные попытки

Важно не забыть про две вещи: • количество попыток выполнения задачи (--tries или свойство $tries в Job) • максимальное время работы задачи (--timeout или свойство $timeout)

Пример: class GenerateReport implements ShouldQueue { public int $timeout = 120; public int $tries = 3; }

Так задача не будет висеть вечно и не будет долбить внешний сервис бесконечно.

Чек-лист перед выносом в очередь • Логика действительно не нужна прямо сейчас пользователю • Вся нужная информация передаётся в Job через параметры, а не берётся из сессии • Логика идемпотентна: повторный запуск не создаёт дубли и кривые данные • Настроены таймауты и количество попыток • Есть логи и базовый мониторинг очередей

Частые ошибки • В Job передают целые модели вместо ID, потом ловят проблемы с сериализацией • Тяжёлый код остаётся в контроллере, а Job превращается в тонкую обёртку • Не настраивают мониторинг очередей — воркер умер, а все думают, что система работает • Не разделяют очереди по типам задач (high, default, low), из-за чего тяжёлый отчёт блокирует отправку критичных уведомлений

Итог

Очереди в Laravel — это базовый инструмент, а не «опция на потом». Как только один HTTP-запрос начинает делать больше одной-двух тяжёлых операций, выносите их в Job. Пользователю — быстрый ответ, серверу — спокойная жизнь, вам — предсказуемое поведение проекта.

#php #laravel #backend #devops

Очереди в Laravel: когда пора перестать всё делать в запросе
Иногда один HTTP-запрос тащит за собой отправку писем, генерацию PDF, импорт из Excel и ещё пол-проекта | Сетка — социальная сеть от hh.ru