> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Laravel Horizon

> 說明如何運用 Laravel Horizon 以視覺化方式管理與監控 Redis 佇列，涵蓋儀表板、平衡策略、Supervisor 設定與通知。

## Horizon 是什麼

[Laravel Horizon](https://github.com/laravel/horizon) 是為 Laravel **Redis 佇列專用**的監控儀表板。它可即時視覺化 Job 的吞吐量、執行時間、失敗狀況，並以程式碼管理 worker 設定。

<Info>
  Horizon 是擴充佇列基本功能的套件。請先熟悉[佇列與 Job](/zh-TW/queues)後再閱讀本頁。此外，後端必須使用 [Redis](/zh-TW/redis)。
</Info>

```mermaid theme={null}
flowchart LR
    Browser["瀏覽器"] -->|"/horizon"| Dashboard["Horizon<br>儀表板"]
    Dashboard -->|"監控 / 控制"| Horizon["Horizon<br>程序"]
    Horizon -->|"Job 管理"| Redis["Redis<br>Queue"]
    Redis -->|"取得 Job"| Worker1["Worker 1"]
    Redis -->|"取得 Job"| Worker2["Worker 2"]
    Redis -->|"取得 Job"| Worker3["Worker 3"]
```

## 安裝

<Warning>
  Horizon 使用 Redis 作為佇列後端，請確認 `config/queue.php` 的 `QUEUE_CONNECTION` 為 `redis`。目前尚未支援 Redis Cluster。
</Warning>

透過 Composer 安裝：

```shell theme={null}
composer require laravel/horizon
```

安裝完成後發布 Horizon 的資產與設定檔。

```shell theme={null}
php artisan horizon:install
```

此指令會產生 `config/horizon.php` 與 `app/Providers/HorizonServiceProvider.php`。

## 設定

### config/horizon.php 結構

`config/horizon.php` 集中管理所有 worker 設定，其核心為 `environments` 選項。

```php theme={null}
'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,
        ],
    ],
],
```

<Info>
  Horizon 內部使用名為 `horizon` 的 Redis 連線，請不要在 `config/database.php` 中把此名稱用於其他連線。
</Info>

### CSP nonce（Content Security Policy）

若要在 Horizon 視圖中為 `script` / `style` 標籤加上 [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) 所需的 [nonce 屬性](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/nonce)，可以使用 `Horizon::cspNonce`。因為每次請求都需要新的 nonce，通常會在中介軟體中呼叫。

```php theme={null}
use Closure;
use Illuminate\Http\Request;
use Laravel\Horizon\Horizon;
use Symfony\Component\HttpFoundation\Response;

public function handle(Request $request, Closure $next): Response
{
    Horizon::cspNonce('csp-nonce');

    return $next($request);
}
```

將此中介軟體加入 `config/horizon.php` 的 `middleware` 選項。

```php theme={null}
'middleware' => [
    'web',
    App\Http\Middleware\AddHorizonCspNonce::class,
],
```

### Supervisor

每個環境可包含一或多個「Supervisor」。Supervisor 是 worker 群組的管理單位，同一環境內可同時執行多個具備不同佇列、平衡策略與程序數的 Supervisor。

### 預設值

透過 `defaults` 選項為所有 Supervisor 設定共同的預設值。

```php theme={null}
'defaults' => [
    'supervisor-1' => [
        'connection' => 'redis',
        'queue' => ['default'],
        'balance' => 'auto',
        'tries' => 1,
        'timeout' => 60,
        'maxProcesses' => 1,
    ],
],
```

### 維護模式

應用程式處於維護模式時，Horizon 預設不會處理 Job。若要強制處理，可使用 `force` 選項。

```php theme={null}
'environments' => [
    'production' => [
        'supervisor-1' => [
            'force' => true,
        ],
    ],
],
```

### Job 最大重試次數

```php theme={null}
'environments' => [
    'production' => [
        'supervisor-1' => [
            'tries' => 10,
        ],
    ],
],
```

`tries` 設為 `0` 表示允許無限次重試。

### Job 逾時

```php theme={null}
'environments' => [
    'production' => [
        'supervisor-1' => [
            'timeout' => 60,
        ],
    ],
],
```

<Warning>
  `timeout` 請比 `config/queue.php` 的 `retry_after` 短數秒。此外，`auto` 平衡策略可能強制結束執行超過此值的 Job。
</Warning>

### backoff（重試等待時間）

指定拋出例外後至下次重試的等待秒數。

```php theme={null}
// 固定值
'backoff' => 10,

// 階段式（指數退避）
'backoff' => [1, 5, 10],
```

### 其他 worker 選項

除了 `tries`、`timeout`、`backoff`，各 Supervisor 還支援控制 worker 程序行為與自動重啟時機的選項。定期重啟長時間執行的程序是防止記憶體洩漏的好習慣。

```php theme={null}
'environments' => [
    'production' => [
        'supervisor-1' => [
            // ...
            'memory' => 128,
            'maxJobs' => 1000,
            'maxTime' => 3600,
            'sleep' => 3,
            'rest' => 0,
            'nice' => 0,
        ],
    ],
],
```

* `memory` — worker 程序在重啟前可使用的最大記憶體量（MB），預設 `128`
* `maxJobs` — 重啟前處理的 Job 數，`0` 代表無限，預設 `0`
* `maxTime` — 重啟前可運作的秒數，`0` 代表不以時間重啟，預設 `0`
* `sleep` — 沒有 Job 時，下次輪詢前等待的秒數，預設 `3`
* `rest` — 每 Job 處理之間暫停的秒數，預設 `0`
* `nice` — worker 程序的優先度（"niceness"），值越大優先度越低，預設 `0`

## 平衡策略

Horizon 提供 3 種 worker 平衡策略。

<AccordionGroup>
  <Accordion title="auto（預設）">
    依佇列負載自動調整 worker 數，並以 `minProcesses` 與 `maxProcesses` 指定範圍。

    ```php theme={null}
    'supervisor-1' => [
        'balance' => 'auto',
        'autoScalingStrategy' => 'time', // 或 'size'
        'minProcesses' => 1,
        'maxProcesses' => 10,
        'balanceMaxShift' => 1,
        'balanceCooldown' => 3,
    ],
    ```

    * `time` — 以清空佇列的預估時間進行擴縮
    * `size` — 依佇列中 Job 數量擴縮

    <Info>
      `auto` 策略下佇列順序並不代表優先度。若要強制優先順序，請使用多個 Supervisor。
    </Info>
  </Accordion>

  <Accordion title="simple">
    固定 worker 數，並平均分配給指定的佇列。

    ```php theme={null}
    'supervisor-1' => [
        'balance' => 'simple',
        'processes' => 10,
        'queue' => ['default', 'notifications'],
    ],
    ```

    在上例中會分別配置 5 個 worker 給 `default` 與 `notifications`。
  </Accordion>

  <Accordion title="false（不平衡）">
    嚴格依佇列列表順序優先。行為與 Laravel 預設佇列系統相同，但仍會依積累量調整 worker 數。

    ```php theme={null}
    'supervisor-1' => [
        'balance' => false,
        'queue' => ['default', 'notifications'],
        'minProcesses' => 1,
        'maxProcesses' => 10,
    ],
    ```

    `default` 佇列的 Job 永遠會優先於 `notifications`。
  </Accordion>
</AccordionGroup>

## 儀表板授權

Horizon 儀表板可透過 `/horizon` 存取。在本機環境預設任何人都可存取，但**正式環境**中應以 Gate 定義限制存取權限。

編輯 `app/Providers/HorizonServiceProvider.php` 的 `gate()` 方法。

```php theme={null}
use App\Models\User;
use Illuminate\Support\Facades\Gate;

protected function gate(): void
{
    Gate::define('viewHorizon', function (User $user) {
        return in_array($user->email, [
            'admin@example.com',
        ]);
    });
}
```

若不需要認證（例如以 IP 限制保護），可以把參數改為可選。

```php theme={null}
Gate::define('viewHorizon', function (User $user = null) {
    // 以 IP 位址等進行限制時
    return true;
});
```

## 啟動 Horizon

### 基本指令

```shell theme={null}
# 啟動
php artisan horizon

# 暫停 / 繼續
php artisan horizon:pause
php artisan horizon:continue

# 暫停 / 繼續特定 Supervisor
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`。

```shell theme={null}
npm install --save-dev chokidar
php artisan horizon:listen

# 在 Docker / Vagrant 環境
php artisan horizon:listen --poll
```

### 使用 Supervisor 持續運行

正式環境中透過 Supervisor 讓 Horizon 持續運作。

#### 安裝 Supervisor

```shell theme={null}
sudo apt-get install supervisor
```

#### 建立設定檔

建立 `/etc/supervisor/conf.d/horizon.conf`：

```ini theme={null}
[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
```

<Warning>
  `stopwaitsecs` 請設定比最長 Job 執行時間更大的值。太小的話 Supervisor 會在 Job 執行過程中強制中止。
</Warning>

#### 啟動 Supervisor

```shell theme={null}
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start horizon
```

#### 部署時

每次部署後請重啟 Horizon 以套用變更。

```shell theme={null}
php artisan horizon:terminate
```

只要 Supervisor 設為 `autostart=true` / `autorestart=true`，關閉後就會自動重啟。

## Job 管理

### 標籤

Horizon 會自動偵測 Job 相關的 Eloquent 模型並加上標籤。

```php theme={null}
// 接收 Video 模型（id=1）的 Job → 自動附加 "App\Models\Video:1" 標籤
RenderVideo::dispatch(Video::find(1));
```

若要手動定義標籤，可實作 `tags()` 方法。

```php theme={null}
class RenderVideo implements ShouldQueue
{
    /**
     * @return array<int, string>
     */
    public function tags(): array
    {
        return ['render', 'video:'.$this->video->id];
    }
}
```

在事件監聽器中，事件實例會傳給 `tags()`。

```php theme={null}
class SendRenderNotifications implements ShouldQueue
{
    public function tags(VideoRendered $event): array
    {
        return ['video:'.$event->video->id];
    }
}
```

### 靜音化

不希望顯示於儀表板「已完成 Job」清單的 Job，可在 `config/horizon.php` 靜音化。

```php theme={null}
'silenced' => [
    App\Jobs\ProcessPodcast::class,
],

// 以標籤靜音
'silenced_tags' => [
    'notifications',
],
```

也可以透過實作 `Silenced` 介面達成。

```php theme={null}
use Laravel\Horizon\Contracts\Silenced;

class ProcessPodcast implements ShouldQueue, Silenced
{
    use Queueable;
    // ...
}
```

## 指標與監控

Horizon 的指標儀表板會顯示 Job / 佇列的吞吐量與執行時間。請安排定期擷取快照。

```php theme={null}
// routes/console.php
use Illuminate\Support\Facades\Schedule;

Schedule::command('horizon:snapshot')->everyFiveMinutes();
```

可透過 `config/horizon.php` 的 `metrics.trim_snapshots` 設定為指標圖表保留的快照數量。此設定以「數量」而非「時間」限制，因此實際保留期間會隨 `horizon:snapshot` 執行頻率變動。

```php theme={null}
'metrics' => [
    'trim_snapshots' => [
        'job' => 24,
        'queue' => 24,
    ],
],
```

要移除所有指標資料，執行下列指令：

```shell theme={null}
php artisan horizon:clear-metrics
```

## Job 失敗通知

當佇列等待時間過長時可以收到通知。請在 `app/Providers/HorizonServiceProvider.php` 的 `boot()` 中設定。

```php theme={null}
use Laravel\Horizon\Horizon;

public function boot(): void
{
    parent::boot();

    Horizon::routeMailNotificationsTo('admin@example.com');
    Horizon::routeSlackNotificationsTo('slack-webhook-url', '#ops');
    Horizon::routeSmsNotificationsTo('15556667777');
}
```

### 等待時間的閾值

在 `config/horizon.php` 的 `waits` 中設定觸發通知的等待秒數。

```php theme={null}
'waits' => [
    'redis:critical' => 30,  // 等待 30 秒以上通知
    'redis:default' => 60,
    'redis:batch' => 120,
],
```

設為 `0` 表示停用該佇列的通知。

## 失敗 Job 管理

失敗的 Job 可以用 ID 或 UUID 刪除。

```shell theme={null}
# 刪除特定失敗 Job
php artisan horizon:forget 5

# 刪除所有失敗 Job
php artisan horizon:forget --all
```

若要清除佇列中的所有 Job：

```shell theme={null}
# 清除預設佇列
php artisan horizon:clear

# 清除特定佇列
php artisan horizon:clear --queue=emails
```

## 升級

進行 Horizon 主版本升級時，請務必參閱[升級指南](https://github.com/laravel/horizon/blob/master/UPGRADE.md)。

## 相關頁面

<CardGroup cols={2}>
  <Card title="佇列與 Job" href="/zh-TW/queues">
    Laravel 佇列的基礎。說明 Job 的建立、派發、批次處理與失敗處理。
  </Card>

  <Card title="Redis" href="/zh-TW/redis">
    作為 Horizon 後端所需的 Redis 設定與用法。
  </Card>
</CardGroup>


## Related topics

- [快取](/zh-TW/cache.md)
- [套件的版本相容性管理](/zh-TW/advanced/package-versioning.md)
- [Queue 與 Job](/zh-TW/queues.md)
- [Laravel Sentinel — 路由保護 Middleware 調查](/zh-TW/blog/sentinel-introduction.md)
- [2026 年 4 月 Laravel 更新](/zh-TW/blog/changelog/202604.md)
