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.
- Называет реальные риски, диагностику и критерий корректности.
- Связывает ответ с текущей документацией и миграционными ограничениями.