Laravel Horizon
- Вступление
- Установка
- Настройка
- Авторизация в информационной панели (dashboard)
- Максимальное количество попыток выполнения задания
- Тайм-аут задания
- Отсрочка задания
- Заглушить задания
- Стратегии балансировки
- Автоматическая балансировка
- Простая балансировка
- Без балансировки
- Обновление Horizon
- Запуск Horizon
- Развертывание Horizon (deploy)
- Теги
- Уведомления
- Метрики
- Удаление невыполненных заданий
- Удаление заданий из очередей
Вступление
Прежде чем углубляться в Laravel Horizon, вам следует ознакомиться с базовыми службами очередей Laravel. Horizon дополняет очередь Laravel дополнительными функциями, которые могут сбивать с толку, если вы еще не знакомы с основными функциями, предлагаемыми Laravel.
Laravel Horizon предоставляет красивую панель управления и конфигурацию для ваших очередей Redis, работающих на Laravel. Horizon позволяет легко отслеживать ключевые показатели системы очередей, такие как пропускная способность, время выполнения и сбои заданий.
При использовании Horizon вся ваша конфигурация обработчика очереди хранится в одном простом файле конфигурации. Определив конфигурацию воркеров (worker) приложения в файле с контролем версий, вы можете легко масштабировать или изменять воркеры очереди приложения при развертывании.

Установка
Laravel Horizon требует, чтобы вы использовали Redis для управления очередью. Следовательно, вы должны убедиться, что соединение с очередью настроено на
redis
в файле конфигурации приложенияconfig/queue.php
.
Вы можете установить Horizon в свой проект с помощью диспетчера пакетов Composer:
composer require laravel/horizon
После установки Horizon опубликуйте его ресурсы с помощью Artisan-команды horizon:install
:
php artisan horizon:install
Настройка
После публикации ресурсов Horizon его основной файл конфигурации будет расположен по адресу config/horizon.php
. Этот файл конфигурации позволяет вам настроить параметры обработчика очереди для приложения. Каждый вариант конфигурации включает описание своего назначения, поэтому обязательно внимательно изучите этот файл.
Horizon использует Redis-соединение с именем «horizon». Это имя соединения Redis зарезервировано и не должно назначаться другому Redis-соединению в файле конфигурации
database.php
или в качестве значения параметраuse
в файле конфигурацииhorizon.php
.
Окружение
Основным параметром конфигурации Horizon, с которым вы должны ознакомиться после установки, является параметр конфигурации environments
. Этот параметр конфигурации представляет собой массив сред, в которых работает ваше приложение, и определяет параметры рабочего процесса для каждой среды. По умолчанию эта запись содержит окружение production
и local
. Однако вы можете добавлять дополнительные среды по мере необходимости:
'environments' => [
'production' => [
'supervisor-1' => [
'maxProcesses' => 10,
'balanceMaxShift' => 1,
'balanceCooldown' => 3,
],
],
'local' => [
'supervisor-1' => [
'maxProcesses' => 3,
],
],
],
Вы также можете определить среду с подстановочными знаками (*
), которая будет использоваться, когда не будет обнаружено другой подходящей среды:
'environments' => [
// ...
'*' => [
'supervisor-1' => [
'maxProcesses' => 3,
],
],
],
Когда вы запускаете Horizon, он будет использовать параметры конфигурации рабочего процесса для среды, в которой работает ваше приложение. Как правило, среда определяется значением APP_ENV
переменной среды. Например, стандартная локальная среда Horizon настроена на запуск трех рабочих процессов и автоматическое выравнивание количества рабочих процессов, назначенных каждой очереди. По умолчанию рабочая среда настроена на запуск максимум 10 рабочих процессов и автоматический баланс количества рабочих процессов, назначенных каждой очереди.
Вы должны убедиться, что раздел
environment
файла конфигурацииhorizon
содержит запись для каждой среды, в которой вы планируете запускать Horizon.
Supervisors (Наблюдатели)
Как вы можете увидеть в файле конфигурации Horizon по умолчанию — каждая среда может содержать один или несколько “supervisors” (наблюдателей). По умолчанию в файле конфигурации этот supervisor определяется как supervisor-1
; однако вы можете называть своих supervisors как хотите. Каждый supervisor, по сути, отвечает за “наблюдение” за группой рабочих процессов и заботится о балансировке рабочих процессов по очередям.
Вы можете добавить дополнительных “supervisors” в данную среду, если хотите определить новую группу рабочих процессов, которые должны выполняться в этой среде. Вы можете сделать это, если хотите определить другую стратегию балансировки или количество рабочих процессов для данной очереди, используемой вашим приложением.
Режим Обслуживания
Во время работы вашего приложения в режиме обслуживания, отложенные задания не будут обрабатываться Horizon, если опция force
для supervisor не определена как true
в файле конфигурации Horizon:
'environments' => [
'production' => [
'supervisor-1' => [
// ...
'force' => true,
],
],
],
Значения по умолчанию
В файле конфигурации Horizon по умолчанию вы заметите параметр конфигурации defaults
. Эта опция конфигурации определяет значения по умолчанию для Supervisors приложения. Значения конфигурации супервизора по умолчанию будут объединены с конфигурацией супервизора для каждой среды, что позволит вам избежать ненужного повторения при определении супервизоров.
Авторизация в информационной панели (dashboard)
Доступ к информационной панели Horizon можно получить по маршруту /horizon
. По умолчанию вы сможете получить доступ к этой панели инструментов только в локальной среде. Однако в файле app/Providers/HorizonServiceProvider.php
есть определение шлюза авторизации. Этот шлюз контролирует доступ к Horizon во внешних средах. Вы можете настроить этот шлюз по мере необходимости, чтобы ограничить доступ к вашему приложению Horizon:
/**
* Регистрация шлюза Horizon.
*
* Этот шлюз определяют, кто может получить доступ к Horizon во внешней среде.
*/
protected function gate(): void
{
Gate::define('viewHorizon', function (User $user) {
return in_array($user->email, [
'taylor@laravel.com',
]);
});
}
Альтернативные стратегии аутентификации
Помните, что Laravel автоматически добавляет к шлюзу аутентифицированного пользователя замыкание (closure). Если ваше приложение обеспечивает безопасность Horizon с помощью другого метода, например ограничения IP-адресов, то пользователям Horizon может и не требоваться “аутентификация”. Следовательно, нужно будет изменить написание функции (сигнатуру) выше с function (User $user)
на function (User $user = null)
, чтобы Laravel не требовал аутентификации.
Максимальное количество попыток выполнения задания
Прежде чем настраивать эти параметры, убедитесь, что вы знакомы со стандартными сервисами очередей Laravel и концепцией «попыток».
Вы можете определить максимальное количество попыток, которые может выполнить задание, в настройках супервизора:
'environments' => [
'production' => [
'supervisor-1' => [
// ...
'tries' => 10,
],
],
],
Этот параметр аналогичен параметру
--tries
при использовании команды Artisan для обработки очередей.
Настройка параметра tries
важна при использовании промежуточных программ, таких как WithoutOverlapping
или RateLimited
, поскольку они потребляют попытки. Для решения этой проблемы измените значение конфигурации tries
либо на уровне супервизора, либо определив свойство $tries
в классе задания.
Если параметр tries
не задан, Horizon по умолчанию использует одну попытку, если только класс задания не определяет $tries
, который имеет приоритет над конфигурацией Horizon.
Установка tries
или $tries
в 0 допускает неограниченное количество попыток, что идеально подходит, когда количество попыток неизвестно. Чтобы предотвратить бесконечные сбои, можно ограничить количество разрешенных исключений, установив свойство $maxExceptions
в классе задания.
Тайм-аут задания
Аналогичным образом, вы можете задать значение timeout
на уровне супервизора, которое определяет, сколько секунд рабочий процесс может выполнять задание, прежде чем оно будет принудительно завершено. После завершения задание будет либо выполнено повторно, либо помечено как неудавшееся, в зависимости от конфигурации очереди:
'environments' => [
'production' => [
'supervisor-1' => [
// ...¨
'timeout' => 60,
],
],
],
Значение
timeout
всегда должно быть как минимум на несколько секунд короче значенияretry_after
, указанного в файле конфигурацииconfig/queue.php
. В противном случае ваши задания могут быть обработаны дважды.
Отсрочка задания
Вы можете определить значение backoff
на уровне супервизора, чтобы указать, как долго Horizon должен ждать, прежде чем повторить попытку выполнения задания, которое столкнулось с необработанным исключением:
'environments' => [
'production' => [
'supervisor-1' => [
// ...
'backoff' => 10,
],
],
],
Вы также можете настроить «экспоненциальные» задержки, используя массив для значения backoff
. В этом примере задержка между попытками составит 1 секунду для первой попытки, 5 секунд для второй, 10 секунд для третьей и 10 секунд для каждой последующей попытки, если остались ещё попытки:
'environments' => [
'production' => [
'supervisor-1' => [
// ...
'backoff' => [1, 5, 10],
],
],
],
Заглушить задания
Иногда вам может быть неинтересно просматривать определенные задания, отправленные вашим приложением или сторонними пакетами. Вместо того чтобы эти задания занимали место в вашем списке “Завершенных заданий”, вы можете заглушить их. Для начала добавьте имя класса задания в параметр конфигурации silenced
в файле конфигурации horizon
вашего приложения:
'silenced' => [
App\Jobs\ProcessPodcast::class,
],
В качестве альтернативы задание, которое вы хотите заглушить, может реализовать интерфейс Laravel\Horizon\Contracts\Silenced
. Если задание реализует этот интерфейс, оно будет автоматически заглушено, даже если оно отсутствует в массиве конфигурации silenced
:
use Laravel\Horizon\Contracts\Silenced;
class ProcessPodcast implements ShouldQueue, Silenced
{
use Queueable;
// ...
}
Стратегии балансировки
Каждый супервизор может обрабатывать одну или несколько очередей, но в отличие от стандартной системы очередей Laravel, Horizon позволяет выбирать из трех стратегий балансировки обработчиков: auto
, simple
и false
.
Автоматическая балансировка
Стратегия auto
, используемая по умолчанию, корректирует количество рабочих процессов в очереди в зависимости от текущей нагрузки. Например, если в очереди notifications
1000 ожидающих заданий, а очередь default
пуста, Horizon будет выделять дополнительные рабочие процессы в очередь notifications
, пока она не опустеет.
При использовании стратегии auto
вы также можете настроить параметры конфигурации minProcesses
и maxProcesses
:
minProcesses
определяет минимальное количество рабочих процессов в очереди. Это значение должно быть больше или равно 1.maxProcesses
определяет максимальное общее количество рабочих процессов, до которого Horizon может масштабироваться по всем очередям. Это значение обычно должно быть больше количества очередей, умноженного на значениеminProcesses
. Чтобы предотвратить запуск процессов супервизором, можно установить это значение равным 0.
Например, вы можете настроить Horizon для поддержки по крайней мере одного процесса на очередь и масштабировать в общей сложности до 10 рабочих процессов:
'environments' => [
'production' => [
'supervisor-1' => [
'connection' => 'redis',
'queue' => ['default', 'notifications'],
'balance' => 'auto',
'autoScalingStrategy' => 'time',
'minProcesses' => 1,
'maxProcesses' => 10,
'balanceMaxShift' => 1,
'balanceCooldown' => 3,
],
],
],
Параметр конфигурации autoScalingStrategy
определяет, как Horizon будет распределять дополнительные рабочие процессы по очередям. Вы можете выбрать одну из двух стратегий:
- Стратегия
time
будет назначать работников на основе общего расчетного времени, необходимого для очистки очереди. - Стратегия
size
будет назначать работников на основе общего количества заданий в очереди.
Конфигурационные значения balanceMaxShift
и balanceCooldown
определяют скорость масштабирования Horizon для удовлетворения потребностей рабочих процессов. В приведенном выше примере каждые три секунды будет создаваться или удаляться не более одного нового процесса. Вы можете изменять эти значения в соответствии с потребностями вашего приложения.
Приоритеты очереди и автоматическая балансировка
При использовании стратегии балансировки auto
Horizon не устанавливает строгий приоритет между очередями. Порядок очередей в конфигурации супервизора не влияет на назначение рабочих процессов. Вместо этого Horizon использует выбранную стратегию autoScalingStrategy
для динамического распределения рабочих процессов в зависимости от нагрузки на очередь.
Например, в следующей конфигурации высокая очередь не имеет приоритета над очередью по умолчанию, несмотря на то, что она стоит первой в списке:
'environments' => [
'production' => [
'supervisor-1' => [
// ...
'queue' => ['high', 'default'],
'minProcesses' => 1,
'maxProcesses' => 10,
],
],
],
Если вам необходимо обеспечить относительный приоритет между очередями, вы можете определить несколько супервизоров и явно выделить ресурсы обработки:
'environments' => [
'production' => [
'supervisor-1' => [
// ...
'queue' => ['default'],
'minProcesses' => 1,
'maxProcesses' => 10,
],
'supervisor-2' => [
// ...
'queue' => ['images'],
'minProcesses' => 1,
'maxProcesses' => 1,
],
],
],
В этом примере очередь по умолчанию queue
может масштабироваться до 10 процессов, тогда как очередь images
ограничена одним процессом. Такая конфигурация гарантирует независимое масштабирование очередей.
При диспетчеризации ресурсоёмких заданий иногда лучше назначать их в отдельную очередь с ограниченным значением
maxProcesses
. В противном случае эти задания могут потреблять чрезмерное количество ресурсов ЦП и перегружать систему.
Простая балансировка
Стратегия simple
равномерно распределяет рабочие процессы по указанным очередям. При использовании этой стратегии Horizon не масштабирует количество рабочих процессов автоматически. Вместо этого используется фиксированное количество процессов:
'environments' => [
'production' => [
'supervisor-1' => [
// ...
'queue' => ['default', 'notifications'],
'balance' => 'simple',
'processes' => 10,
],
],
],
В приведенном выше примере Horizon назначит 5 процессов каждой очереди, разделив общее количество процессов (10) поровну.
Если вы хотите контролировать количество рабочих процессов, назначенных каждой очереди индивидуально, вы можете определить несколько супервизоров:
'environments' => [
'production' => [
'supervisor-1' => [
// ...
'queue' => ['default'],
'balance' => 'simple',
'processes' => 10,
],
'supervisor-notifications' => [
// ...
'queue' => ['notifications'],
'balance' => 'simple',
'processes' => 2,
],
],
],
При такой конфигурации Horizon назначит 10 процессов в очередь «по умолчанию» и 2 процесса в очередь «уведомлений».
Без балансировки
Если параметр balance
установлен в значение false
, Horizon обрабатывает очереди строго в порядке их перечисления, аналогично стандартной системе очередей Laravel. Однако он всё равно будет масштабировать количество рабочих процессов, если задания начнут накапливаться:
'environments' => [
'production' => [
'supervisor-1' => [
// ...
'queue' => ['default', 'notifications'],
'balance' => false,
'minProcesses' => 1,
'maxProcesses' => 10,
],
],
],
В приведённом выше примере задания в очереди default
всегда имеют приоритет над заданиями в очереди notifications
. Например, если в очереди default
находится 1000 заданий, а в очереди notifications
— только 10, Horizon полностью обработает все задания default
, прежде чем обрабатывать задания из очереди notifications
.
Вы можете контролировать возможности Horizon по масштабированию рабочих процессов с помощью параметров minProcesses
и maxProcesses
:
minProcesses
определяет минимальное количество рабочих процессов. Это значение должно быть больше или равно 1.maxProcesses
определяет максимальное общее количество рабочих процессов, до которого Horizon может масштабироваться.
Обновление Horizon
При обновлении до новой версии Horizon важно внимательно изучить руководство по обновлению.
Запуск Horizon
После того как вы настроили свои супервизоры (supervisors) и рабочие процессы (workers) в файле конфигурации приложения config/horizon.php
, вы можете запустить Horizon, используя Artisan-команду horizon
. Эта единственная команда запустит все настроенные рабочие процессы для текущей среды:
php artisan horizon
Вы можете приостановить процесс Horizon и дать ему указание продолжить обработку заданий, используя Artisan-команды horizon:pause
и horizon:continue
:
php artisan horizon:pause
php artisan horizon:continue
Вы также можете приостановить и продолжить определенные Horizon супервизоры, используя Artisan-команды horizon:pause-supervisor
и horizon:continue-supervisor
:
php artisan horizon:pause-supervisor supervisor-1
php artisan horizon:continue-supervisor supervisor-1
Вы можете проверить текущий статус процесса Horizon, используя Artisan-команду horizon:status
:
php artisan horizon:status
Вы можете проверить текущий статус конкретного супервизора Horizon с помощью Artisan-команды horizon:supervisor-status
:
php artisan horizon:supervisor-status supervisor-1
Вы можете корректно завершить процесс Horizon, используя Artisan-команду horizon:terminate
. Все задания, которые в настоящее время обрабатываются, будут завершены, а затем Horizon прекратит работу:
php artisan horizon:terminate
Развертывание Horizon (deploy)
Когда вы будете готовы развернуть Horizon на фактическом сервере приложения, вам следует настроить монитор процессов для отслеживания командой php artisan horizon
и перезапустить ее, если она неожиданно завершится. Не волнуйтесь, ниже мы обсудим, как установить монитор процессов.
Во время процесса развертывания приложения вы должны дать команду Horizon завершить процесс, чтобы он был перезапущен монитором процессов и получил изменения кода:
php artisan horizon:terminate
Установка Supervisor
Supervisor – это монитор процессов для операционной системы Linux, который автоматически перезапустит ваш процесс horizon
, если он перестанет выполняться. Чтобы установить Supervisor в Ubuntu, вы можете использовать следующую команду. Если вы не используете Ubuntu, вы, вероятно, можете установить Supervisor с помощью диспетчера пакетов вашей операционной системы:
sudo apt-get install supervisor
Если настройка Supervisor сама по себе кажется утомительной, рассмотрите возможность использования Laravel Cloud, который может управлять фоновыми процессами для ваших приложений Laravel.
Настройка Supervisor
Файлы конфигурации супервизора обычно хранятся в каталоге вашего сервера /etc/supervisor/conf.d
. В этом каталоге вы можете создать любое количество файлов конфигурации, которые определяют для супервизора, как следует контролировать процессы. Например, давайте создадим файл horizon.conf
, который запускает и отслеживает процесс horizon
:
[program:horizon]
process_name=%(program_name)s
command=php /home/forge/example.com/artisan horizon
autostart=true
autorestart=true
user=forge
redirect_stderr=true
stdout_logfile=/home/forge/example.com/horizon.log
stopwaitsecs=3600
При определении конфигурации вашего супервизора вы должны убедиться, что значение stopwaitsecs
больше, чем количество секунд, потребляемых вашим самым длительным выполняемым заданием. В противном случае Supervisor может удалить ваш процесс задания до того, как оно завершит обработку.
Хотя приведенные выше примеры являются действительными для серверов на основе Ubuntu, местоположение и расширение файла, ожидаемые для файлов конфигурации супервизора, могут отличаться для других операционных систем серверов. Пожалуйста, обратитесь к документации вашего сервера для получения дополнительной информации.
Запуск Supervisor
После создания файла конфигурации вы можете обновить конфигурацию Supervisor и запустить отслеживаемые процессы, используя следующие команды:
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start horizon
Для получения дополнительной информации о запуске Supervisor обратитесь к документации Supervisor.
Теги
Horizon позволяет назначать “теги” (tags) заданиям, включая почтовые сообщения, широковещательные события, уведомления и прослушиватели событий в очереди. Фактически, Horizon будет интеллектуально и автоматически помечать большинство заданий в зависимости от моделей Eloquent, прикрепленных к заданию. Например, взгляните на следующее задание (job):
<?php
namespace App\Jobs;
use App\Models\Video;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
class RenderVideo implements ShouldQueue
{
use Queueable;
/**
* Создаем новый экземпляр задания.
*/
public function __construct(
public Video $video,
) {}
/**
* Выполнение задания.
*/
public function handle(): void
{
// ...
}
}
Если это задание поставлено в очередь с экземпляром App\Models\Video
с атрибутом id
равным 1
, то оно автоматически получит тег App\Models\Video:1
. Это потому, что Horizon будет искать в свойствах задания любые модели Eloquent. Если модели Eloquent будут найдены, Horizon разумно пометит задание, используя имя класса модели и первичный ключ:
use App\Jobs\RenderVideo;
use App\Models\Video;
$video = Video::find(1);
RenderVideo::dispatch($video);
Самостоятельное тегирование заданий
Если вы хотите самостоятельно определить теги для одного из объектов в очереди, вы можете определить в классе метод “tags()”:
class RenderVideo implements ShouldQueue
{
/**
* Получаем теги, которые должны быть назначены заданию.
*
* @return array<int, string>
*/
public function tags(): array
{
return ['render', 'video:'.$this->video->id];
}
}
Самостоятельное тегирование слушателей событий
При получении тегов для слушателя событий в очереди Horizon автоматически передаст экземпляр события методу tags
, что позволит вам добавить данные события к тегам:
class SendRenderNotifications implements ShouldQueue
{
/**
* Получаем теги, которые должны быть назначены прослушивателю.
*
* @return array<int, string>
*/
public function tags(VideoRendered $event): array
{
return ['video:'.$event->video->id];
}
}
Уведомления
При настройке Horizon для отправки уведомлений Slack или SMS необходимо ознакомиться с предварительными условиями для соответствующего канала уведомлений.
Если вы хотите получать уведомления, когда одна из ваших очередей имеет длительное время ожидания, вы можете использовать методы Horizon::routeMailNotificationsTo
, Horizon::routeSlackNotificationsTo
и Horizon::routeSmsNotificationsTo
. Вы можете вызвать эти методы из метода boot
провайдера вашего приложения App\Providers\HorizonServiceProvider
:
/**
* Загрузчик сервисов приложения.
*/
public function boot(): void
{
parent::boot();
Horizon::routeSmsNotificationsTo('15556667777');
Horizon::routeMailNotificationsTo('example@example.com');
Horizon::routeSlackNotificationsTo('slack-webhook-url', '#channel');
}
Настройка пороговых значений времени ожидания уведомлений
Вы можете настроить, сколько секунд будет считаться “долгим ожиданием” в файле конфигурации Horizon config/horizon.php
. Параметр конфигурации waits
в этом файле позволяет вам настраивать пороги ожидания для каждой комбинации соединения/очереди. Любый комбинации соединения/очереди, не определённые в waits
, по умолчанию будут иметь порог ожидания в 60 секунд:
'waits' => [
'redis:critical' => 30,
'redis:default' => 60,
'redis:batch' => 120,
],
Метрики
Horizon включает в себя панель метрик, которая предоставляет информацию о времени ожидания задач и очереди, а также пропускной способности. Чтобы записывать информацию в эту панель, вы должны настроить Artisan-команду Horizon snapshot
для выполнения каждые пять минут в файле routes/console.php
вашего приложения:
use Illuminate\Support\Facades\Schedule;
Schedule::command('horizon:snapshot')->everyFiveMinutes();
Если вы хотите удалить все данные метрик, вы можете вызвать команду Artisan horizon:clear-metrics
:
php artisan horizon:clear-metrics
Удаление невыполненных заданий
Если вы хотите удалить неудавшееся задание, можете использовать команду horizon:forget
. Команда horizon:forget
принимает идентификатор или UUID неудачного задания в качестве своего единственного аргумента:
php artisan horizon:forget 5
Если вы хотите удалить все неудачные задания, вы можете указать опцию --all
для команды horizon:forget
:
php artisan horizon:forget --all
Удаление заданий из очередей
Если вы хотите удалить все задания из очереди приложения по умолчанию, то вы можете сделать это с помощью Artisan-команды horizon:clear
:
php artisan horizon:clear
Можно добавить опцию queue
для удаления заданий из определенной очереди:
php artisan horizon:clear --queue=emails