메인 콘텐츠로 건너뛰기

Horizon 이란

Laravel Horizon은 Laravel의 Redis 큐 전용 감시 대시보드입니다. 잡의 스루풋·실행 시간·실패 상황을 실시간으로 가시화하고, 워커 설정을 코드로 관리할 수 있습니다.
Horizon은 큐의 기초 기능을 확장하는 패키지입니다. 먼저 큐와 잡의 기본을 이해하고 나서 진행해 주십시오. 또한 백엔드에는 반드시 Redis가 필요합니다.

설치

Horizon은 Redis를 큐 백엔드로 사용합니다. config/queue.phpQUEUE_CONNECTIONredis로 설정되어 있는지 확인해 주십시오. 현시점에서 Redis Cluster에는 대응하고 있지 않습니다.
Composer로 설치합니다.
composer require laravel/horizon
설치 후 Horizon의 애셋과 설정 파일을 공개합니다.
php artisan horizon:install
이 명령어로 config/horizon.phpapp/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,
        ],
    ],
],
tries0으로 하면 무제한 재시도를 허가합니다.

잡의 타임아웃

'environments' => [
    'production' => [
        'supervisor-1' => [
            'timeout' => 60,
        ],
    ],
],
timeoutconfig/queue.phpretry_after보다 수 초 짧은 값을 설정해 주십시오. 또한 auto 밸런스 전략에서는 이 값보다 긴 잡을 강제 종료시키는 경우가 있습니다.

백오프(재시도의 대기 시간)

예외 발생 후 재시도까지의 대기 초 수를 지정합니다.
// 고정값
'backoff' => 10,

// 단계적(지수 백오프)
'backoff' => [1, 5, 10],

밸런스 전략

Horizon에는 3종류의 워커 밸런스 전략이 있습니다.
큐의 부하에 따라 워커 수를 자동 조정합니다. minProcessesmaxProcesses로 범위를 지정합니다.
'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'],
],
위에서는 defaultnotifications에 각각 5프로세스씩 할당됩니다.
큐를 열거한 순서대로 엄격히 우선합니다. Laravel 기본의 큐 시스템과 같은 동작이지만, 적체에 따라 워커 수를 스케일링합니다.
'supervisor-1' => [
    'balance' => false,
    'queue' => ['default', 'notifications'],
    'minProcesses' => 1,
    'maxProcesses' => 10,
],
default 큐의 잡이 항상 notifications 큐보다 먼저 처리됩니다.

대시보드의 인가

Horizon의 대시보드는 /horizon 라우트에서 접근할 수 있습니다. 로컬 환경에서는 기본적으로 누구나 접근할 수 있지만, 운영 환경에서는 게이트 정의로 접근을 제한합니다. app/Providers/HorizonServiceProvider.phpgate() 메서드를 편집합니다.
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.phpboot() 메서드에서 설정합니다.
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.phpwaits 옵션으로 통지 트리거가 되는 대기 초 수를 설정합니다.
'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의 설정과 사용법.
마지막 수정일 2026년 7월 13일