Horizon 이란
Laravel Horizon 은 Laravel의 Redis 큐 전용 감시 대시보드입니다. 잡의 스루풋·실행 시간·실패 상황을 실시간으로 가시화하고, 워커 설정을 코드로 관리할 수 있습니다.
Horizon은 큐의 기초 기능을 확장하는 패키지입니다. 먼저 큐와 잡 의 기본을 이해하고 나서 진행해 주십시오. 또한 백엔드에는 반드시 Redis 가 필요합니다.
Horizon은 Redis를 큐 백엔드로 사용합니다. config/queue.php의 QUEUE_CONNECTION이 redis로 설정되어 있는지 확인해 주십시오. 현시점에서 Redis Cluster에는 대응하고 있지 않습니다.
Composer로 설치합니다.
composer require laravel/horizon
설치 후 Horizon의 애셋과 설정 파일을 공개합니다.
php artisan horizon:install
이 명령어로 config/horizon.php와 app/Providers/HorizonServiceProvider.php가 생성됩니다.
config/horizon.php 의 구성
config/horizon.php는 워커의 설정을 모두 관리하는 파일입니다. 중심이 되는 설정이 environments 옵션입니다.
'environments' => [
'production' => [
'supervisor-1' => [
'connection' => 'redis' ,
'queue' => [ 'default' , 'notifications' ],
'balance' => 'auto' ,
'autoScalingStrategy' => 'time' ,
'minProcesses' => 1 ,
'maxProcesses' => 10 ,
'balanceMaxShift' => 1 ,
'balanceCooldown' => 3 ,
'tries' => 3 ,
'timeout' => 60 ,
],
],
'local' => [
'supervisor-1' => [
// 그 외의 값은 defaults 섹션에서 상속됩니다
'maxProcesses' => 3 ,
],
],
],
Horizon은 내부에서 horizon이라는 이름의 Redis 접속을 사용합니다. config/database.php에서 이 이름을 다른 접속에 사용하지 마십시오.
슈퍼바이저(Supervisor)
각 환경은 하나 이상의 “슈퍼바이저”를 가질 수 있습니다. 슈퍼바이저는 워커 그룹의 관리 단위이며, 서로 다른 큐·밸런스 전략·프로세스 수를 갖는 여러 슈퍼바이저를 동일 환경에서 움직일 수 있습니다.
기본값
defaults 옵션으로 모든 슈퍼바이저에 적용되는 기본값을 설정할 수 있습니다.
'defaults' => [
'supervisor-1' => [
'connection' => 'redis' ,
'queue' => [ 'default' ],
'balance' => 'auto' ,
'tries' => 1 ,
'timeout' => 60 ,
'maxProcesses' => 1 ,
],
],
유지보수 모드
애플리케이션이 유지보수 모드일 때, Horizon은 기본적으로 잡을 처리하지 않습니다. 강제로 처리시키려면 force 옵션을 사용합니다.
'environments' => [
'production' => [
'supervisor-1' => [
'force' => true ,
],
],
],
잡의 최대 시도 횟수
'environments' => [
'production' => [
'supervisor-1' => [
'tries' => 10 ,
],
],
],
tries를 0으로 하면 무제한 재시도를 허가합니다.
잡의 타임아웃
'environments' => [
'production' => [
'supervisor-1' => [
'timeout' => 60 ,
],
],
],
timeout은 config/queue.php의 retry_after보다 수 초 짧은 값을 설정해 주십시오. 또한 auto 밸런스 전략에서는 이 값보다 긴 잡을 강제 종료시키는 경우가 있습니다.
백오프(재시도의 대기 시간)
예외 발생 후 재시도까지의 대기 초 수를 지정합니다.
// 고정값
'backoff' => 10 ,
// 단계적(지수 백오프)
'backoff' => [ 1 , 5 , 10 ],
밸런스 전략
Horizon에는 3종류의 워커 밸런스 전략이 있습니다.
큐의 부하에 따라 워커 수를 자동 조정합니다. minProcesses와 maxProcesses로 범위를 지정합니다. 'supervisor-1' => [
'balance' => 'auto' ,
'autoScalingStrategy' => 'time' , // 또는 'size'
'minProcesses' => 1 ,
'maxProcesses' => 10 ,
'balanceMaxShift' => 1 ,
'balanceCooldown' => 3 ,
],
time — 큐를 비울 때까지의 추정 시간으로 스케일링
size — 큐 내의 잡 수로 스케일링
auto 전략에서는 큐의 순서가 우선도를 의미하지 않습니다. 우선도를 강제하고 싶은 경우 여러 슈퍼바이저를 사용해 주십시오.
워커 수를 고정하고, 지정한 큐에 균등하게 분배합니다. 'supervisor-1' => [
'balance' => 'simple' ,
'processes' => 10 ,
'queue' => [ 'default' , 'notifications' ],
],
위에서는 default와 notifications에 각각 5프로세스씩 할당됩니다.
큐를 열거한 순서대로 엄격히 우선합니다. Laravel 기본의 큐 시스템과 같은 동작이지만, 적체에 따라 워커 수를 스케일링합니다. 'supervisor-1' => [
'balance' => false ,
'queue' => [ 'default' , 'notifications' ],
'minProcesses' => 1 ,
'maxProcesses' => 10 ,
],
default 큐의 잡이 항상 notifications 큐보다 먼저 처리됩니다.
대시보드의 인가
Horizon의 대시보드는 /horizon 라우트에서 접근할 수 있습니다. 로컬 환경에서는 기본적으로 누구나 접근할 수 있지만, 운영 환경 에서는 게이트 정의로 접근을 제한합니다.
app/Providers/HorizonServiceProvider.php의 gate() 메서드를 편집합니다.
use App\Models\ User ;
use Illuminate\Support\Facades\ Gate ;
protected function gate () : void
{
Gate :: define ( 'viewHorizon' , function ( User $user ) {
return in_array ( $user -> email , [
'[email protected] ' ,
]);
});
}
인증을 필요로 하지 않는 경우(IP 제한 등으로 보호하고 있는 경우), 인수를 옵셔널로 합니다.
Gate :: define ( 'viewHorizon' , function ( User $user = null ) {
// IP 주소 등으로 제한하고 있는 경우
return true ;
});
Horizon 의 기동
기본 명령어
# 기동
php artisan horizon
# 일시 정지 / 재개
php artisan horizon:pause
php artisan horizon:continue
# 특정 슈퍼바이저의 일시 정지 / 재개
php artisan horizon:pause-supervisor supervisor-1
php artisan horizon:continue-supervisor supervisor-1
# 스테이터스 확인
php artisan horizon:status
php artisan horizon:supervisor-status supervisor-1
# 그레이스풀 셧다운
php artisan horizon:terminate
로컬 개발: 자동 재기동
파일 변경을 감지해 Horizon을 자동 재기동하려면 horizon:listen 명령어를 사용합니다.
npm install --save-dev chokidar
php artisan horizon:listen
# Docker / Vagrant 환경에서는
php artisan horizon:listen --poll
Supervisor 에 의한 상시 기동
운영 환경에서는 Supervisor를 사용해 Horizon을 상시 가동시킵니다.
Supervisor 의 설치
sudo apt-get install supervisor
설정 파일의 작성
/etc/supervisor/conf.d/horizon.conf를 작성합니다.
[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가 잡을 도중에 강제 종료시켜 버립니다.
Supervisor 의 기동
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start horizon
배포 시
코드를 배포할 때마다 Horizon을 재기동해 변경을 반영합니다.
php artisan horizon:terminate
Supervisor가 autostart=true / autorestart=true로 되어 있으면, 종료 후에 자동으로 재기동됩니다.
잡의 관리
Horizon은 잡에 관련된 Eloquent 모델을 자동 검출해 태그를 붙입니다.
// Video 모델(id=1)을 받는 잡 → 자동으로 "App\Models\Video:1" 태그가 붙음
RenderVideo :: dispatch ( Video :: find ( 1 ));
수동으로 태그를 정의하려면 tags() 메서드를 구현합니다.
class RenderVideo implements ShouldQueue
{
/**
* @return array < int , string>
*/
public function tags () : array
{
return [ 'render' , 'video:' . $this -> video -> id ];
}
}
이벤트 리스너에서는 이벤트 인스턴스가 tags() 메서드에 전달됩니다.
class SendRenderNotifications implements ShouldQueue
{
public function tags ( VideoRendered $event ) : array
{
return [ 'video:' . $event -> video -> id ];
}
}
사일런트화
대시보드의 “완료된 잡” 리스트에 표시하고 싶지 않은 잡은 config/horizon.php에서 사일런트화할 수 있습니다.
'silenced' => [
App\Jobs\ ProcessPodcast :: class ,
],
// 태그 단위로 사일런트화
'silenced_tags' => [
'notifications' ,
],
Silenced 인터페이스를 구현하는 방법도 있습니다.
use Laravel\Horizon\Contracts\ Silenced ;
class ProcessPodcast implements ShouldQueue , Silenced
{
use Queueable ;
// ...
}
메트릭과 모니터링
Horizon의 메트릭 대시보드에는 잡·큐의 스루풋과 실행 시간이 표시됩니다. 정기적으로 스냅숏을 취득하기 위한 스케줄을 설정합니다.
// routes/console.php
use Illuminate\Support\Facades\ Schedule ;
Schedule :: command ( 'horizon:snapshot' ) -> everyFiveMinutes ();
메트릭 데이터를 모두 삭제하려면 다음을 실행합니다.
php artisan horizon:clear-metrics
잡 실패의 통지
큐의 대기 시간이 길어졌을 때 통지를 받을 수 있습니다. app/Providers/HorizonServiceProvider.php의 boot() 메서드에서 설정합니다.
use Laravel\Horizon\ Horizon ;
public function boot () : void
{
parent :: boot ();
Horizon :: routeMailNotificationsTo ( '[email protected] ' );
Horizon :: routeSlackNotificationsTo ( 'slack-webhook-url' , '#ops' );
Horizon :: routeSmsNotificationsTo ( '15556667777' );
}
대기 시간의 임계값
config/horizon.php의 waits 옵션으로 통지 트리거가 되는 대기 초 수를 설정합니다.
'waits' => [
'redis:critical' => 30 , // 30초 이상 대기로 통지
'redis:default' => 60 ,
'redis:batch' => 120 ,
],
0을 설정하면 그 큐의 통지는 무효화됩니다.
실패 잡의 관리
실패한 잡은 ID 또는 UUID로 삭제할 수 있습니다.
# 특정 실패 잡을 삭제
php artisan horizon:forget 5
# 모든 실패 잡을 삭제
php artisan horizon:forget --all
큐의 잡을 모두 소거하려면 다음을 사용합니다.
# 기본 큐 소거
php artisan horizon:clear
# 특정 큐 소거
php artisan horizon:clear --queue=emails
업그레이드
Horizon의 메이저 버전 업데이트 시에는 업그레이드 가이드 를 반드시 확인해 주십시오.
관련 페이지
큐와 잡 Laravel 큐의 기본. 잡의 작성·디스패치·배치 처리·실패 처리를 설명.
Redis Horizon의 백엔드로서 필요한 Redis의 설정과 사용법.