Очереди в Laravel: как выбрать драйвер и настроить воркеры
Разбираем, чем отличаются database, Redis и SQS в очередях Laravel, как считать число воркеров и почему задачи иногда обрабатываются дважды.

С чего начинается разговор о очередях
Задача уходит в очередь, воркер её берёт, падает на середине — и пользователь получает два письма вместо одного. Или наоборот: задача теряется, потому что драйвер не умеет возвращать её в очередь. Это не абстрактные страшилки, а типичные последствия того, что драйвер очереди выбрали по первой строке документации, а воркеры запустили командой из чужого гайда.
Здесь разбираем три вещи: чем реально отличаются драйверы database, redis и sqs, сколько воркеров запускать и как их держать живыми, и почему одна и та же задача выполняется дважды. Смежные темы — batch-джобы, rate limiting и Horizon как надстройка над Redis — обозначаю, но не разворачиваю. Материал для Laravel 11.x; в 10.x конфигурация очередей почти та же, ключевые отличия отмечаю по ходу.
Драйверы: за что вы платите в каждом
Драйвер задаётся в config/queue.php и переменной QUEUE_CONNECTION. Выбор влияет не на код джобы, а на надёжность, скорость и цену эксплуатации.
database
Очередь живёт в таблице базы данных. Никакой дополнительной инфраструктуры: если у вас уже есть PostgreSQL или MySQL, очередь заведётся командой php artisan make:queue-table и миграцией. Плата за простоту — нагрузка на ту же базу, где лежат бизнес-данные. Каждый воркер опрашивает таблицу, берёт строку, блокирует её. При сотнях задач в секунду и десятке воркеров это выливается в конкуренцию за строки и рост нагрузки на диск.
Подходит для проектов, где очередь — это отложенная отправка писем и генерация отчётов, а не тысячи событий в минуту.
redis
Задачи хранятся в списках Redis, забираются атомарной операцией. Это быстро: Redis держит данные в памяти, конкуренции за строки нет. Redis умеет отложенные задачи (через sorted set) и в связке с Laravel Horizon даёт панель мониторинга и автоскейлинг воркеров.
Плата — отдельный сервис, который надо держать живым и настроить на сохранение данных (appendonly), иначе при перезапуске Redis очередь с задачами исчезнет. Для большинства нагруженных проектов это дефолтный выбор.
sqs
Amazon SQS снимает с вас эксплуатацию: очередь как управляемый сервис. Масштабируется без вашего участия, переживает падение приложения. Плата — вендор-лок на AWS, оплата за запросы и задержки сети. SQS не гарантирует строгий порядок в стандартной очереди и имеет лимит видимости сообщения (visibility timeout), с которым надо согласовать таймаут ваших джоб.
| Критерий | database | redis | sqs |
|---|---|---|---|
| Доп. инфраструктура | нет | Redis | аккаунт AWS |
| Пропускная способность | низкая-средняя | высокая | высокая |
| Отложенные задачи | да | да | до 15 минут |
| Мониторинг | ручной | Horizon | консоль AWS |
| Риск потери задач | низкий | при неверном appendonly | низкий |
Драйвер выбирают не по скорости, а по тому, сколько вы готовы платить за эксплуатацию. database — ноль инфраструктуры и потолок по нагрузке. redis — свой сервис и высокая скорость. sqs — чужая эксплуатация и счёт от AWS.
Воркеры: сколько и как запускать
Воркер — это долгоживущий процесс, запущенный командой php artisan queue:work. Он держит приложение загруженным в память и берёт задачи одну за другой. Не путайте с queue:listen — тот перезагружает фреймворк на каждой задаче, работает медленнее и нужен разве что в разработке.
Базовый запуск
# Laravel 11.x, драйвер redis, обработка очередей default и emails
php artisan queue:work redis --queue=emails,default --tries=3 --max-time=3600Разбор флагов:
--queue=emails,default— приоритет: сначала опустошается emails, потом default;--tries=3— задача повторяется до трёх раз при падении, потом уходит в failed_jobs;--max-time=3600— воркер сам завершится через час, чтобы супервизор перезапустил его и освободил память.
Сколько воркеров
Точной формулы нет, но есть ориентиры. Число воркеров зависит от характера задач:
- Задачи упираются в CPU (обработка изображений, расчёты) — воркеров примерно по числу ядер. Больше не ускорит, только добавит переключений контекста.
- Задачи ждут ввода-вывода (HTTP-запросы к внешним API, отправка писем) — воркеров можно больше числа ядер, потому что процесс большую часть времени простаивает в ожидании ответа.
Начните с числа ядер, посмотрите на глубину очереди и время ожидания задачи, добавляйте воркеров, пока очередь перестанет накапливаться. Слепо ставить 50 воркеров на 4 ядра — способ положить и базу, и внешний API.
Как держать воркеры живыми
Процесс queue:work рано или поздно завершится: по --max-time, из-за фатальной ошибки или деплоя. Его нужно перезапускать автоматически. Стандартный инструмент — Supervisor. Пример конфигурации /etc/supervisor/conf.d/laravel-worker.conf:
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/app/artisan queue:work redis --queue=emails,default --tries=3 --max-time=3600
autostart=true
autorestart=true
stopwaitsecs=3600
numprocs=4
user=www-data
redirect_stderr=true
stdout_logfile=/var/www/app/storage/logs/worker.logЗдесь numprocs=4 — как раз число одновременных воркеров. Важный параметр — stopwaitsecs: он должен быть не меньше самого долгого --max-time, иначе Supervisor убьёт воркер посреди задачи при остановке.
Перезапуск при деплое
Воркер держит код в памяти, поэтому после выката новой версии он продолжит работать на старом коде. После деплоя обязательно выполняйте:
php artisan queue:restartЭта команда не убивает процессы мгновенно, а ставит флаг: каждый воркер завершится после текущей задачи, а Supervisor поднимет его уже с новым кодом.
Почему задача выполняется дважды
Самый частый и болезненный сюрприз очередей — задача обрабатывается больше одного раза. Причин несколько.
Задача упала после побочного эффекта
Джоба списала деньги, отправила уведомление, а потом упала на последней строке. С --tries=3 Laravel запустит её снова — и деньги спишутся повторно. Очереди дают гарантию «хотя бы один раз», а не «ровно один раз». Проектируйте джобы идемпотентными: проверяйте, не выполнено ли действие уже, прежде чем повторять.
Таймаут короче реального времени задачи
Флаг --timeout (по умолчанию 60 секунд) убивает воркер, если задача не уложилась. Но задача уже могла успеть сделать половину работы. При повторе — снова с начала. Держите --timeout больше реального максимума и меньше visibility timeout у SQS.
Защита от повторов
Для критичных задач используйте ShouldBeUnique — интерфейс, не пускающий в очередь дубликат по ключу, пока предыдущая не отработала. Схематично:
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
class ChargeUser implements ShouldQueue, ShouldBeUnique
{
public function __construct(public int $userId) {}
// Уникальность по идентификатору пользователя
public function uniqueId(): string
{
return (string) $this->userId;
}
// Блокировка держится не дольше 10 минут
public int $uniqueFor = 600;
}Уникальность требует кеша с блокировками — Redis или memcached. С драйвером кеша array она работать не будет.
Что настроить дальше
После того как воркеры запущены и держатся Supervisor, займитесь наблюдаемостью. Смотрите на три показателя в проде:
- глубина очереди — сколько задач ждёт обработки прямо сейчас;
- время ожидания — сколько задача лежит от постановки до выполнения;
- рост таблицы
failed_jobs— если она пухнет, где-то падают джобы, и это надо чинить, а не игнорировать.
Если вы на Redis — поставьте Laravel Horizon: он даёт эти метрики из коробки и умеет автоматически менять число воркеров под нагрузку. Batch-джобы, rate limiting и middleware для очередей — отдельные темы, к которым имеет смысл переходить, когда базовая связка драйвер плюс воркеры под Supervisor уже работает стабильно.
Задачи: математика, физика, химия: Разбор задачи по шагам с проверкой и похожей задачей
Спросить за 10 ₽Источники: Laravel Queues — официальная документация, Laravel Horizon — официальная документация
Частые вопросы
Что выбрать для нового проекта без большой нагрузки — database или redis?
У меня Laravel 10.x, а не 11.x — команды из статьи подойдут?
Воркер запущен, но задачи не обрабатываются — что смотреть?
Почему задача выполнилась дважды, если я не ставил --tries больше единицы?
Нужен ли Supervisor, или можно запускать queue:work вручную?
Сколько воркеров нужно на проекте с отправкой писем?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.