LaravelMiddleTechnical

Как работает Horizon и как мониторить очереди?

Horizon — дашборд и супервизор для Redis-очередей Laravel. Он запускает воркеры, балансирует нагрузку через auto-scaling, сохраняет историю задач в Redis и предоставляет веб-интерфейс для мониторинга.

Что такое Laravel Horizon

Horizon — официальный пакет для управления Redis-очередями в Laravel. Он заменяет стандартный queue:work-демон, добавляя супервизор, автомасштабирование воркеров и веб-дашборд для наблюдения за задачами в реальном времени.

Установка и запуск

// Установка
composer require laravel/horizon
php artisan horizon:install  // публикует config/horizon.php и дашборд-ассеты
php artisan migrate          // создаёт таблицы для метрик (если нужно)

// Запуск в разработке
php artisan horizon

// Продакшн: Supervisor управляет процессом Horizon
// /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/log/horizon.log

Конфигурация супервизоров и воркеров

// config/horizon.php
return [
    'defaults' => [
        'supervisor-1' => [
            'connection' => 'redis',
            'queue'      => ['high', 'default', 'low'],
            'balance'    => 'auto',       // auto, simple, false
            'minProcesses' => 1,
            'maxProcesses' => 10,
            'balanceMaxShift'   => 1,    // процессов добавляется за раз
            'balanceCooldown'   => 3,    // секунд между балансировками
            'tries'    => 3,
            'timeout'  => 60,
            'memory'   => 128,
        ],
    ],
    'environments' => [
        'production' => [
            'supervisor-1' => [
                'maxProcesses' => 20,
            ],
        ],
        'local' => [
            'supervisor-1' => [
                'maxProcesses' => 3,
            ],
        ],
    ],
];

Ключевые Artisan-команды

php artisan horizon          // запуск
php artisan horizon:pause   // приостановка (воркеры доедают текущие задачи)
php artisan horizon:continue // возобновление
php artisan horizon:terminate // graceful shutdown (Supervisor перезапустит)
php artisan horizon:status  // статус мастер-процесса
php artisan horizon:clear   // очистить задачи из всех очередей
php artisan horizon:snapshot // записать метрики throughput/runtime вручную

Деплой без простоя

// В Makefile / деплой-скрипте
php artisan horizon:terminate
// Supervisor автоматически поднимет новый процесс с новым кодом
// НЕ нужно делать horizon:restart — terminate + supervisor это уже перезапуск

Мониторинг метрик

Horizon сохраняет в Redis историю выполненных задач (по умолчанию 1 час). Дашборд доступен по адресу /horizon. Закрыть доступ можно через gate в HorizonServiceProvider:

// app/Providers/HorizonServiceProvider.php
protected function gate(): void
{
    Gate::define('viewHorizon', function (User $user) {
        return in_array($user->email, [
            'admin@example.com',
        ]);
    });
}

Метрики throughput и runtime Horizon собирает через horizon:snapshot, которую нужно планировать через Scheduler:

// routes/console.php (Laravel 11+)
Schedule::command('horizon:snapshot')->everyFiveMinutes();

Теги для группировки задач

class ProcessPodcast implements ShouldQueue
{
    public function tags(): array
    {
        // Видно в дашборде; удобно искать задачи по пользователю или объекту
        return ['podcast:' . $this->podcast->id, 'user:' . $this->podcast->user_id];
    }
}

Подводные камни

  • Horizon работает только с Redis: database, SQS и другие драйверы не поддерживаются. Если QUEUE_CONNECTION не redis — Horizon просто не запустится.
  • Забытый horizon:snapshot в Scheduler: без него графики throughput/runtime в дашборде останутся пустыми, хотя очередь работает.
  • horizon:restart не существует: правильный способ перезагрузки — horizon:terminate, после чего Supervisor поднимает новый процесс.
  • Автомасштабирование balance=auto медленно реагирует: по умолчанию balanceCooldown=3 секунды и balanceMaxShift=1 процесс — при пиковой нагрузке воркеры наращиваются постепенно, очередь может накапливаться.
  • Память воркера не сбрасывается: у каждого воркера есть лимит memory (МБ). При превышении процесс сам завершается и Horizon перезапускает его — убедитесь, что лимит разумный, иначе воркеры будут циклически перезапускаться.
  • Срок хранения заданий в Redis: trim_recent_jobs по умолчанию 3600 сек. Для отладки старых ошибок увеличьте его, иначе история пропадёт до того, как вы успеете посмотреть.
  • Дашборд открыт в production по умолчанию: без настройки gate любой пользователь в local-окружении увидит дашборд; в production gate обязателен.

Common mistakes

  • Отвечать определением без production-сценария.
  • Не называть runtime boundary, security boundary или failure mode.
  • Игнорировать версию API, observability и тестовую проверку.

What the interviewer is testing

  • Объясняет механизм своими словами и без выдуманных API.
  • Называет реальные риски, диагностику и критерий корректности.
  • Связывает ответ с текущей документацией и миграционными ограничениями.

Sources

Related topics