Laravel Horizon
번역일: 2026년 6월 25일
Laravel Horizon
소개
NOTE
Laravel Horizon을 사용하기 전에, Laravel의 기본 큐 서비스에 먼저 익숙해지는 것을 권장합니다. Horizon은 기본 큐 기능을 확장한 도구이므로, 큐 개념을 모른 채 Horizon을 사용하면 혼란스러울 수 있습니다.
Laravel Horizon은 Laravel의 Redis 큐를 위한 아름다운 대시보드와 코드 기반 설정을 제공합니다. Horizon을 사용하면 Job 처리량, 실행 시간, 실패 현황 등 큐 시스템의 핵심 지표를 한눈에 모니터링할 수 있습니다.
Horizon에서는 모든 큐 워커 설정이 하나의 설정 파일로 관리됩니다. 이 파일을 버전 관리 시스템(Git 등)에 포함시키면, 배포 시 워커 프로세스의 수를 조정하거나 구성을 변경하는 작업이 훨씬 수월해집니다.
설치
WARNING
Laravel Horizon은 반드시 Redis를 큐 드라이버로 사용해야 합니다. config/queue.php 파일에서 큐 연결이 redis로 설정되어 있는지 확인하세요. 현재 Horizon은 Redis Cluster와는 호환되지 않습니다.
Composer로 Horizon을 설치합니다:
composer require laravel/horizon설치 후, horizon:install Artisan 명령어로 Horizon의 에셋을 퍼블리시합니다:
php artisan horizon:install설정
에셋을 퍼블리시하면 config/horizon.php 파일이 생성됩니다. 이 파일에서 큐 워커의 동작 방식을 세부적으로 설정할 수 있으며, 각 옵션마다 설명 주석이 포함되어 있으니 꼼꼼히 살펴보시기 바랍니다.
WARNING
Horizon은 내부적으로 horizon이라는 이름의 Redis 연결을 사용합니다. 이 이름은 Horizon 전용으로 예약되어 있으므로, database.php 설정 파일이나 horizon.php의 use 옵션 값으로 다른 용도로 사용하지 마세요.
환경(Environments)
설치 후 가장 먼저 살펴봐야 할 항목은 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 환경 변수를 기준으로 현재 환경에 맞는 워커 설정을 사용합니다. 예를 들어, 기본 local 환경은 워커 3개로 시작하고, production 환경은 최대 10개의 워커를 사용하며 각 큐에 자동으로 워커를 분배합니다.
WARNING
Horizon을 실행할 모든 환경이 horizon 설정 파일의 environments 항목에 등록되어 있어야 합니다.
슈퍼바이저(Supervisors)
Horizon의 기본 설정 파일에서 볼 수 있듯이, 각 환경에는 하나 이상의 "슈퍼바이저"를 정의할 수 있습니다. 기본값은 supervisor-1이지만 이름은 자유롭게 지정할 수 있습니다. 슈퍼바이저는 워커 프로세스 그룹을 관리하고, 큐 간 워커 분배를 담당합니다.
특정 큐에 대해 다른 밸런싱 전략이나 프로세스 수를 적용하고 싶다면, 슈퍼바이저를 여러 개 정의하면 됩니다.
점검 모드(Maintenance Mode)
애플리케이션이 점검 모드일 때는 기본적으로 Horizon이 큐 Job을 처리하지 않습니다. 점검 모드 중에도 Job을 처리하려면 슈퍼바이저 설정에서 force 옵션을 true로 설정하세요:
'environments' => [
'production' => [
'supervisor-1' => [
// ...
'force' => true,
],
],
],기본값(Default Values)
horizon.php 설정 파일에는 defaults 옵션이 있습니다. 이 옵션에 슈퍼바이저의 공통 기본값을 정의해 두면, 각 환경의 슈퍼바이저 설정과 병합되어 중복 설정을 줄일 수 있습니다.
대시보드 인증
Horizon 대시보드는 /horizon 경로로 접근할 수 있습니다. 기본적으로 local 환경에서만 접근이 허용됩니다. app/Providers/HorizonServiceProvider.php 파일에는 비-로컬 환경에서의 접근을 제어하는 인가 게이트가 정의되어 있습니다. 필요에 따라 이 게이트를 수정하여 접근 권한을 설정하세요:
/**
* Horizon 게이트를 등록합니다.
*
* 이 게이트는 비-로컬 환경에서 Horizon에 접근할 수 있는 사용자를 결정합니다.
*/
protected function gate(): void
{
Gate::define('viewHorizon', function (User $user) {
return in_array($user->email, [
'admin@example.com',
]);
});
}대체 인증 방식
Laravel은 게이트 클로저에 인증된 사용자를 자동으로 주입합니다. IP 제한 등 다른 방식으로 Horizon 보안을 처리하는 경우, 사용자가 로그인할 필요가 없을 수 있습니다. 이 경우 클로저 시그니처를 function (User $user)에서 function (User $user = null)로 변경하여 인증을 필수 조건에서 제외하세요.
최대 Job 시도 횟수
NOTE
이 옵션을 조정하기 전에 Laravel의 기본 큐 서비스와 'attempts' 개념을 먼저 확인하세요.
슈퍼바이저 설정에서 Job의 최대 시도 횟수를 지정할 수 있습니다:
'environments' => [
'production' => [
'supervisor-1' => [
// ...
'tries' => 10,
],
],
],NOTE
이 옵션은 Artisan 큐 명령어의 --tries 옵션과 동일한 역할을 합니다.
WithoutOverlapping이나 RateLimited 같은 미들웨어는 시도 횟수를 소모하므로, 이러한 미들웨어를 사용할 때는 tries 값을 적절히 조정해야 합니다. 슈퍼바이저 레벨에서 설정하거나, Job 클래스에 $tries 프로퍼티를 정의하는 방법을 사용할 수 있습니다.
tries를 설정하지 않으면 Horizon은 기본적으로 1회 시도합니다. 단, Job 클래스에 $tries가 정의되어 있으면 해당 값이 Horizon 설정보다 우선합니다.
tries 또는 $tries를 0으로 설정하면 시도 횟수 제한이 없어집니다. 무한 재시도를 허용하되 무한 실패를 방지하려면, Job 클래스의 $maxExceptions 프로퍼티로 허용할 최대 예외 수를 제한하세요.
Job 타임아웃
슈퍼바이저 레벨에서 timeout 값을 설정하면, 워커 프로세스가 Job을 처리할 수 있는 최대 시간(초)을 지정할 수 있습니다. 제한 시간을 초과하면 해당 Job은 강제 종료되며, 큐 설정에 따라 재시도되거나 실패로 처리됩니다:
'environments' => [
'production' => [
'supervisor-1' => [
// ...
'timeout' => 60,
],
],
],WARNING
auto 밸런싱 전략을 사용할 때, Horizon은 처리 중인 워커를 "멈춘(hanging)" 상태로 판단하고 스케일 다운 시 Horizon 타임아웃이 지나면 강제 종료합니다. 따라서 Horizon 타임아웃은 반드시 개별 Job의 타임아웃보다 크게 설정해야 합니다. 그렇지 않으면 Job이 실행 도중 종료될 수 있습니다. 또한, timeout 값은 config/queue.php의 retry_after 값보다 적어도 몇 초 짧게 설정해야 합니다. 그렇지 않으면 동일한 Job이 두 번 처리될 수 있습니다.
Job 백오프
처리되지 않은 예외가 발생했을 때 Job을 재시도하기 전에 대기할 시간(초)을 슈퍼바이저 레벨에서 backoff로 설정할 수 있습니다:
'environments' => [
'production' => [
'supervisor-1' => [
// ...
'backoff' => 10,
],
],
],backoff 값을 배열로 지정하면 지수 백오프를 구성할 수 있습니다. 아래 예시에서는 첫 번째 재시도는 1초, 두 번째는 5초, 세 번째 이후부터는 10초를 대기합니다:
'environments' => [
'production' => [
'supervisor-1' => [
// ...
'backoff' => [1, 5, 10],
],
],
],무음 처리 Job
특정 Job을 "완료된 Job" 목록에 표시하지 않으려면 horizon 설정 파일의 silenced 옵션에 해당 Job 클래스를 추가하세요:
'silenced' => [
App\Jobs\ProcessPodcast::class,
],특정 태그를 가진 Job 전체를 숨기려면 silenced_tags 옵션을 사용하세요:
'silenced_tags' => [
'notifications'
],또는 Job 클래스가 Laravel\Horizon\Contracts\Silenced 인터페이스를 구현하면, silenced 배열에 추가하지 않아도 자동으로 무음 처리됩니다:
use Laravel\Horizon\Contracts\Silenced;
class ProcessPodcast implements ShouldQueue, Silenced
{
use Queueable;
// ...
}밸런싱 전략
각 슈퍼바이저는 하나 이상의 큐를 처리할 수 있습니다. Horizon은 기본 Laravel 큐 시스템과 달리, 워커 분배를 위한 세 가지 전략을 제공합니다: auto, simple, false.
자동 밸런싱 (auto)
기본 전략인 auto는 각 큐의 현재 작업량에 따라 워커 수를 동적으로 조정합니다. 예를 들어, notifications 큐에 1,000개의 대기 Job이 있고 default 큐가 비어 있다면, notifications 큐가 처리될 때까지 해당 큐에 더 많은 워커를 할당합니다.
auto 전략에서는 minProcesses와 maxProcesses를 함께 설정합니다:
minProcesses: 각 큐에 유지할 최소 워커 프로세스 수입니다. 1 이상이어야 합니다.maxProcesses: 전체 큐에 걸쳐 Horizon이 확장할 수 있는 최대 워커 프로세스 수입니다. 일반적으로 큐 수 ×minProcesses보다 크게 설정합니다.0으로 설정하면 프로세스를 전혀 생성하지 않습니다.
아래 예시는 각 큐에 최소 1개의 프로세스를 유지하고, 전체 최대 10개까지 확장하는 설정입니다:
'environments' => [
'production' => [
'supervisor-1' => [
'connection' => 'redis',
'queue' => ['default', 'notifications'],
'balance' => 'auto',
'autoScalingStrategy' => 'time',
'minProcesses' => 1,
'maxProcesses' => 10,
'balanceMaxShift' => 1,
'balanceCooldown' => 3,
],
],
],autoScalingStrategy는 워커를 어떤 기준으로 할당할지 결정합니다:
time: 큐를 모두 처리하는 데 걸리는 예상 시간을 기준으로 워커를 할당합니다.size: 큐에 쌓인 Job 수를 기준으로 워커를 할당합니다.
balanceMaxShift와 balanceCooldown은 스케일링 속도를 제어합니다. 위 예시에서는 3초마다 최대 1개의 프로세스가 생성되거나 제거됩니다. 애플리케이션 특성에 맞게 조정하세요.
큐 우선순위와 자동 밸런싱
auto 전략에서는 큐의 나열 순서가 워커 배분에 영향을 주지 않습니다. Horizon은 autoScalingStrategy에 따라 부하 기반으로 동적으로 워커를 할당합니다.
예를 들어, 아래 설정에서 high 큐가 먼저 나열되어 있더라도 default 큐보다 우선 처리되지는 않습니다:
'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,
],
],
],이 설정에서 default 큐는 최대 10개 프로세스까지 확장될 수 있고, images 큐는 1개로 제한됩니다. 각 큐가 독립적으로 스케일링되는 구조입니다.
NOTE
리소스를 많이 소모하는 Job은 전용 큐에 배치하고 maxProcesses를 제한하는 것이 좋습니다. 그렇지 않으면 해당 Job이 CPU를 과도하게 사용하여 시스템 전체에 부하를 줄 수 있습니다.
단순 밸런싱 (simple)
simple 전략은 지정된 큐에 워커를 균등하게 배분합니다. 자동 스케일링은 수행하지 않으며, 고정된 수의 프로세스를 사용합니다:
'environments' => [
'production' => [
'supervisor-1' => [
// ...
'queue' => ['default', 'notifications'],
'balance' => 'simple',
'processes' => 10,
],
],
],위 예시에서는 총 10개의 프로세스가 두 큐에 5개씩 균등하게 배분됩니다.
큐별로 워커 수를 다르게 지정하려면 슈퍼바이저를 분리하세요:
'environments' => [
'production' => [
'supervisor-1' => [
// ...
'queue' => ['default'],
'balance' => 'simple',
'processes' => 10,
],
'supervisor-notifications' => [
// ...
'queue' => ['notifications'],
'balance' => 'simple',
'processes' => 2,
],
],
],이 설정에서 default 큐에 10개, notifications 큐에 2개의 프로세스가 할당됩니다.
밸런싱 없음 (false)
balance 옵션을 false로 설정하면, Laravel의 기본 큐 동작처럼 큐 목록 순서대로 Job을 처리합니다. 다만, Job이 쌓이면 워커 프로세스 수를 자동으로 늘릴 수 있습니다:
'environments' => [
'production' => [
'supervisor-1' => [
// ...
'queue' => ['default', 'notifications'],
'balance' => false,
'minProcesses' => 1,
'maxProcesses' => 10,
],
],
],이 설정에서는 default 큐의 Job이 notifications 큐보다 항상 우선 처리됩니다. 예를 들어, default 큐에 1,000개, notifications 큐에 10개의 Job이 있다면, default 큐가 완전히 비워진 후에야 notifications 큐를 처리합니다.
minProcesses와 maxProcesses로 워커 프로세스 수의 최솟값과 최댓값을 제어할 수 있습니다:
minProcesses: 유지할 최소 워커 프로세스 수입니다. 1 이상이어야 합니다.maxProcesses: Horizon이 확장할 수 있는 최대 워커 프로세스 수입니다.
Horizon 업그레이드
Horizon의 주요 버전을 업그레이드할 때는 반드시 업그레이드 가이드를 꼼꼼히 검토하세요.
Horizon 실행
config/horizon.php에서 슈퍼바이저와 워커 설정을 마쳤다면, horizon Artisan 명령어로 Horizon을 시작할 수 있습니다. 이 단일 명령어로 현재 환경에 설정된 모든 워커 프로세스가 함께 시작됩니다:
php artisan horizonHorizon 프로세스를 일시 중지하거나 재개하려면 다음 명령어를 사용합니다:
php artisan horizon:pausephp artisan horizon:continue특정 슈퍼바이저만 일시 중지하거나 재개할 수도 있습니다:
php artisan horizon:pause-supervisor supervisor-1php artisan horizon:continue-supervisor supervisor-1Horizon 프로세스의 현재 상태를 확인하려면:
php artisan horizon:status특정 슈퍼바이저의 상태를 확인하려면:
php artisan horizon:supervisor-status supervisor-1Horizon을 정상적으로 종료하려면 horizon:terminate를 사용합니다. 현재 처리 중인 Job을 모두 완료한 후 종료됩니다:
php artisan horizon:terminateHorizon 자동 재시작
로컬 개발 환경에서는 horizon:listen 명령어를 사용할 수 있습니다. 이 명령어는 코드 변경이 감지되면 Horizon을 자동으로 재시작해 주므로, 수동으로 재시작할 필요가 없습니다. 이 기능을 사용하려면 Node.js가 설치되어 있어야 하고, 파일 감시 라이브러리인 Chokidar도 설치해야 합니다:
npm install --save-dev chokidar설치 후 다음 명령어로 Horizon을 시작합니다:
php artisan horizon:listenDocker나 Vagrant 환경에서는 --poll 옵션을 추가하세요:
php artisan horizon:listen --poll감시할 디렉터리와 파일은 config/horizon.php의 watch 옵션으로 설정합니다:
'watch' => [
'app',
'bootstrap',
'config',
'database',
'public/**/*.php',
'resources/**/*.php',
'routes',
'composer.lock',
'.env',
],Horizon 배포
실제 서버에 Horizon을 배포할 때는 프로세스 모니터를 사용하여 php artisan horizon 명령어를 감시하고, 예기치 않게 종료되면 자동으로 재시작하도록 설정해야 합니다.
배포 과정에서 코드 변경 사항을 반영하려면 Horizon을 종료해야 합니다. 프로세스 모니터가 자동으로 재시작해 줄 것입니다:
php artisan horizon:terminateSupervisor 설치
Supervisor는 Linux 운영체제용 프로세스 모니터로, horizon 프로세스가 종료되면 자동으로 재시작해 줍니다. Ubuntu에서는 다음 명령어로 설치할 수 있습니다:
sudo apt-get install supervisorNOTE
Supervisor 설정이 부담스럽다면 Laravel Cloud를 고려해 보세요. Laravel Cloud는 Laravel 애플리케이션의 백그라운드 프로세스를 자동으로 관리해 줍니다.
Supervisor 설정
Supervisor 설정 파일은 일반적으로 /etc/supervisor/conf.d 디