Laravel Horizon: worker не запускается - причины и решение ошибок конфигурации

mr. Cooper 2 часа назад Веб-разработка
Laravel Horizon: worker не запускается - причины и решение ошибок конфигурации

Laravel Horizon - мощный инструмент для управления очередями, но при первом запуске или после изменения конфига он нередко отказывается стартовать. Worker молчит, процессы не появляются, в логах - загадочные сообщения. Эта статья поможет разобраться, почему Horizon не запускает workers, как найти причину и устранить её пошагово. Подойдёт как новичкам, так и тем, кто уже работал с очередями Laravel.

Что такое Laravel Horizon и как он управляет workers

Laravel Horizon - это дашборд и менеджер процессов для очередей на базе Redis. Он запускает и контролирует worker-процессы (php artisan queue:work), следит за нагрузкой и автоматически масштабирует количество воркеров.

Конфигурация Horizon хранится в файле config/horizon.php. Там описываются environments (окружения), supervisors (наборы воркеров) и параметры каждого процесса: очереди, таймауты, количество процессов.

Если что-то настроено неправильно - Horizon стартует, но воркеры не появляются или сразу падают.

Почему Horizon не запускает workers: основные причины

1. Несовпадение окружения (APP_ENV)

Horizon читает конфиг из секции, соответствующей текущему APP_ENV. Если в horizon.php описан только production, а приложение работает в local - воркеры просто не будут запущены.

2. Неверный connection или отсутствие Redis

Horizon работает только с Redis. Если QUEUE_CONNECTION в .env не установлен в redis - воркеры не запустятся.

3. Проблемы с правами и путями PHP

Horizon запускает воркеры как отдельные процессы через php. Если путь к бинарнику PHP не указан или неверный - процессы не стартуют.

4. Ошибки в конфигурационном файле

Опечатки в названиях очередей, неверные типы данных в параметрах (balance, maxProcesses) - всё это приводит к тому, что Horizon молча игнорирует supervisor.

5. Кеш конфигурации не обновлён

После изменения horizon.php забыли сбросить кеш - Horizon продолжает работать по старым настройкам.

Частые ошибки и симптомы

Симптом

Вероятная причина

Horizon запущен, воркеры не появляются

Несовпадение APP_ENV

No supervisors are running

Ошибка конфига или пустое окружение

Connection refused при старте

Redis не запущен или неверный хост

Воркер стартует и сразу падает

Неверный путь к PHP или нехватка памяти

Изменения конфига не применяются

Закешированная конфигурация

Пошаговое решение: как найти и устранить проблему

Шаг 1. Проверьте APP_ENV и секции в horizon.php

php artisan env

Вывод должен совпадать с ключом окружения в config/horizon.php:

'environments' => [
    'production' => [
        'supervisor-1' => [
            'connection' => 'redis',
            'queue'      => ['default'],
            'balance'    => 'auto',
            'processes'  => 10,
            'tries'      => 3,
        ],
    ],

    'local' => [  // ← это окружение должно быть, если APP_ENV=local
        'supervisor-1' => [
            'connection' => 'redis',
            'queue'      => ['default'],
            'balance'    => 'simple',
            'processes'  => 3,
            'tries'      => 3,
        ],
    ],
],

Если секции для вашего окружения нет - добавьте её.

Шаг 2. Убедитесь, что QUEUE_CONNECTION=redis

Откройте .env:

QUEUE_CONNECTION=redis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379

Проверьте, что Redis действительно доступен:

redis-cli ping
# Должно вернуть: PONG

Шаг 3. Сбросьте кеш конфигурации

php artisan config:clear
php artisan horizon:terminate
php artisan horizon

Никогда не меняйте horizon.php без последующей очистки кеша.

Шаг 4. Проверьте путь к PHP в конфиге Horizon

В config/horizon.php есть параметр php:

'path' => env('HORIZON_PATH', base_path()),
// и в supervisor:
'php' => PHP_BINARY, // обычно определяется автоматически

Если Horizon не находит нужный бинарник - укажите явно:

'supervisor-1' => [
    'php' => '/usr/bin/php8.2',
    'connection' => 'redis',
    // ...
],

Шаг 5. Посмотрите логи Horizon

tail -f storage/logs/laravel.log

Или через дашборд Horizon (/horizon) → вкладка Failed Jobs. Там будет точная причина падения.

Шаг 6. Проверьте права на запуск

ls -la storage/logs/
ls -la bootstrap/cache/

Пользователь, под которым работает Horizon (обычно www-data или текущий пользователь), должен иметь права на запись в storage/ и bootstrap/cache/.

chmod -R 775 storage bootstrap/cache

Примеры реальных ошибок и их решение

Ошибка: No supervisors are running

Horizon запущен, дашборд открывается, но в разделе Supervisors - пусто.

Причина: APP_ENV=staging, а в horizon.php есть только local и production.

Решение: добавить секцию staging в environments или изменить APP_ENV на существующее окружение.

Ошибка: Predis\Connection\ConnectionException: Connection refused

Predis\Connection\ConnectionException: Connection refused [tcp://127.0.0.1:6379]

Причина: Redis не запущен.

Решение:

sudo systemctl start redis
sudo systemctl enable redis

Ошибка: воркер запускается, но сразу завершается

В логах видно:

[2024-01-15 12:00:00] local.ERROR: Allowed memory size of 134217728 bytes exhausted

Решение: увеличьте лимит памяти в конфиге supervisor:

'supervisor-1' => [
    'memory' => 256, // мегабайты
    // ...
],

Часто задаваемые вопросы (FAQ)

Q: Horizon запущен, но очередь не обрабатывается - в чём причина?
A: Чаще всего это несовпадение имён очередей. Убедитесь, что в supervisor указана та же очередь (queue), в которую вы отправляете задачи. Например, если задача отправляется в очередь emails, а supervisor слушает default - задача никогда не будет обработана.

Q: Нужно ли перезапускать Horizon после каждого изменения кода?
A: Да. Воркеры Horizon кешируют загруженные классы. После деплоя выполните php artisan horizon:terminate - Horizon автоматически перезапустит процессы. В production это делается через Supervisor (системный демон), а не вручную.

Q: Horizon работает локально, но не работает на сервере - почему?
A: Типичные причины: разные версии PHP, отсутствие расширения pcntl (требуется для управления процессами), или APP_ENV на сервере указывает на несуществующую секцию конфига.

Q: Как проверить, что Horizon реально запустил воркеры?
A: Откройте дашборд /horizon → Supervisors. Там должны отображаться активные процессы. Альтернативно - в терминале:

ps aux | grep queue:work

Q: Можно ли использовать Horizon без Redis?
A: Нет. Horizon работает исключительно с Redis. Для других драйверов (database, SQS) используйте php artisan queue:work напрямую.

Q: Как настроить автозапуск Horizon на сервере?
A: Через системный Supervisor (не Laravel Horizon supervisor). Пример конфига /etc/supervisor/conf.d/horizon.conf:

[program:horizon]
process_name=%(program_name)s
command=php /var/www/html/artisan horizon
autostart=true
autorestart=true
user=www-data
redirect_stderr=true
stdout_logfile=/var/www/html/storage/logs/horizon.log

Q: Что делать, если horizon:terminate не останавливает процессы?
A: Найдите PID вручную и завершите:

ps aux | grep artisan
kill -9 <PID>

Q: Horizon пишет This application is not using the redis queue driver - как исправить?
A: В .env измените QUEUE_CONNECTION=redis и выполните php artisan config:clear.

Полезные советы и лучшие практики

  • Всегда используйте системный Supervisor для автозапуска Horizon в production. Это гарантирует, что процесс поднимется после перезагрузки сервера.

  • Разделяйте очереди по приоритету. Создавайте отдельные supervisors для критичных задач (payments) и фоновых (notifications).

  • Мониторьте метрики. Дашборд Horizon показывает throughput и время выполнения - используйте это для оптимизации количества процессов.

  • Не храните большие объекты в задачах. Передавайте только ID, а данные получайте внутри задачи - это снижает нагрузку на Redis.

  • Настройте оповещения. Horizon поддерживает уведомления о длинных очередях через Horizon::routeMailNotificationsTo() и Slack.

  • Проверяйте версию Horizon после обновления Laravel - мажорные версии фреймворка иногда требуют обновления Horizon.

composer show laravel/horizon | grep versions

Итог

Большинство проблем с запуском workers в Laravel Horizon сводится к трём вещам: несовпадение окружения, неверная конфигурация Redis и устаревший кеш. Прежде чем копать глубже - проверьте APP_ENV, убедитесь что Redis отвечает на PONG, и сбросьте кеш конфигурации. Затем смотрите логи - там всегда есть ответ.

Комментарии

Пока нет комментариев. Будьте первым, кто напишет.

Чтобы оставить комментарий, войдите в аккаунт.

Похожие статьи