跳到內容

Laravel Horizon

簡介

在深入研究 Laravel Horizon 之前,您應該先熟悉 Laravel 的基本佇列服務。如果您尚不熟悉 Laravel 提供的基本佇列功能,Horizon 擴展了 Laravel 的佇列,並增加了額外功能,可能會讓您感到困惑。

Laravel Horizon 為您的 Laravel 驅動的 Redis 佇列提供美觀的儀表板和程式碼驅動的設定。 Horizon 讓您可以輕鬆監控佇列系統的關鍵指標,例如任務吞吐量、執行時間和任務失敗次數。

使用 Horizon 時,您的所有佇列工作程序設定都儲存在單一、簡單的設定檔中。透過在版本控制檔案中定義應用程式的工作程序設定,您可以在部署應用程式時輕鬆擴展或修改應用程式的佇列工作程序。

安裝

Laravel Horizon 要求您使用 Redis 來驅動您的佇列。因此,您應確保您的佇列連線在應用程式的 config/queue.php 設定檔中設定為 redis

您可以使用 Composer 套件管理器將 Horizon 安裝到您的專案中

1composer require laravel/horizon

安裝 Horizon 後,使用 horizon:install Artisan 命令發佈其資源

1php artisan horizon:install

設定

發佈 Horizon 的資源後,其主要設定檔將位於 config/horizon.php。此設定檔可讓您設定應用程式的佇列工作程序選項。每個設定選項都包含其用途的描述,因此請務必徹底瀏覽此檔案。

Horizon 在內部使用名為 horizon 的 Redis 連線。此 Redis 連線名稱已保留,不應在 database.php 設定檔中或作為 horizon.php 設定檔中 use 選項的值指派給另一個 Redis 連線。

環境

安裝後,您應該熟悉的主要 Horizon 設定選項是 environments 設定選項。此設定選項是應用程式執行的環境陣列,並定義每個環境的工作程序程序選項。預設情況下,此條目包含 productionlocal 環境。但是,您可以根據需要自由新增更多環境

1'environments' => [
2 'production' => [
3 'supervisor-1' => [
4 'maxProcesses' => 10,
5 'balanceMaxShift' => 1,
6 'balanceCooldown' => 3,
7 ],
8 ],
9 
10 'local' => [
11 'supervisor-1' => [
12 'maxProcesses' => 3,
13 ],
14 ],
15],

您也可以定義萬用字元環境 (*),當找不到其他符合的環境時將使用它

1'environments' => [
2 // ...
3 
4 '*' => [
5 'supervisor-1' => [
6 'maxProcesses' => 3,
7 ],
8 ],
9],

當您啟動 Horizon 時,它將使用應用程式正在執行的環境的工作程序程序設定選項。通常,環境由 APP_ENV 環境變數的值決定。例如,預設的 local Horizon 環境設定為啟動三個工作程序程序,並自動平衡指派給每個佇列的工作程序程序數量。預設的 production 環境設定為啟動最多 10 個工作程序程序,並自動平衡指派給每個佇列的工作程序程序數量。

您應確保您的 horizon 設定檔的 environments 部分包含您計劃在其上執行 Horizon 的每個環境的條目。

監管者

正如您在 Horizon 的預設設定檔中看到的,每個環境都可以包含一個或多個「監管者」。預設情況下,設定檔將此監管者定義為 supervisor-1;但是,您可以自由地將您的監管者命名為任何您想要的名稱。每個監管者基本上負責「監管」一組工作程序程序,並負責平衡跨佇列的工作程序程序。

如果您想定義一組應在該環境中運行的新工作程序程序,您可以將其他監管者新增到給定環境。如果您想為應用程式使用的給定佇列定義不同的平衡策略或工作程序程序計數,您可以選擇這樣做。

維護模式

當您的應用程式處於維護模式時,除非監管者的 force 選項在 Horizon 設定檔中定義為 true,否則 Horizon 不會處理佇列任務

1'environments' => [
2 'production' => [
3 'supervisor-1' => [
4 // ...
5 'force' => true,
6 ],
7 ],
8],

預設值

在 Horizon 的預設設定檔中,您會注意到 defaults 設定選項。此設定選項指定應用程式監管者的預設值。監管者的預設設定值將合併到每個環境的監管者設定中,讓您在定義監管者時避免不必要的重複。

平衡策略

與 Laravel 的預設佇列系統不同,Horizon 允許您從三種工作程序平衡策略中進行選擇:simpleautofalsesimple 策略在工作程序程序之間平均分配傳入的任務

1'balance' => 'simple',

auto 策略是設定檔的預設策略,它根據佇列的目前工作負載調整每個佇列的工作程序程序數量。例如,如果您的 notifications 佇列有 1,000 個待處理任務,而您的 render 佇列為空,Horizon 將為您的 notifications 佇列分配更多工作程序,直到佇列為空。

使用 auto 策略時,您可以定義 minProcessesmaxProcesses 設定選項,以控制每個佇列的最小程序數和 Horizon 應向上和向下擴展的總工作程序程序數

1'environments' => [
2 'production' => [
3 'supervisor-1' => [
4 'connection' => 'redis',
5 'queue' => ['default'],
6 'balance' => 'auto',
7 'autoScalingStrategy' => 'time',
8 'minProcesses' => 1,
9 'maxProcesses' => 10,
10 'balanceMaxShift' => 1,
11 'balanceCooldown' => 3,
12 'tries' => 3,
13 ],
14 ],
15],

autoScalingStrategy 設定值決定 Horizon 是否會根據清除佇列所需的總時間(time 策略)或佇列上的任務總數(size 策略)為佇列指派更多工作程序程序。

balanceMaxShiftbalanceCooldown 設定值決定 Horizon 將以多快的速度擴展以滿足工作程序需求。在上面的範例中,每三秒最多建立或銷毀一個新程序。您可以根據應用程式的需求自由調整這些值。

balance 選項設定為 false 時,將使用預設的 Laravel 行為,其中佇列按照它們在設定中列出的順序處理。

儀表板授權

可以透過 /horizon 路由存取 Horizon 儀表板。預設情況下,您只能在 local 環境中存取此儀表板。但是,在您的 app/Providers/HorizonServiceProvider.php 檔案中,有一個授權閘道定義。此授權閘道控制對非本機環境中 Horizon 的存取。您可以自由修改此閘道,以限制對 Horizon 安裝的存取

1/**
2 * Register the Horizon gate.
3 *
4 * This gate determines who can access Horizon in non-local environments.
5 */
6protected function gate(): void
7{
8 Gate::define('viewHorizon', function (User $user) {
9 return in_array($user->email, [
11 ]);
12 });
13}

替代驗證策略

請記住,Laravel 會自動將經過驗證的使用者注入閘道閉包中。如果您的應用程式透過另一種方法(例如 IP 限制)提供 Horizon 安全性,則您的 Horizon 使用者可能不需要「登入」。因此,您需要將上面的 function (User $user) 閉包簽章變更為 function (User $user = null),以強制 Laravel 不要求驗證。

靜默任務

有時,您可能對查看應用程式或第三方套件分派的某些任務不感興趣。您可以靜默它們,而不是讓這些任務佔用「已完成任務」列表中的空間。若要開始使用,請將任務的類別名稱新增至應用程式 horizon 設定檔中的 silenced 設定選項

1'silenced' => [
2 App\Jobs\ProcessPodcast::class,
3],

或者,您要靜默的任務可以實作 Laravel\Horizon\Contracts\Silenced 介面。如果任務實作此介面,即使它不存在於 silenced 設定陣列中,它也會自動被靜默

1use Laravel\Horizon\Contracts\Silenced;
2 
3class ProcessPodcast implements ShouldQueue, Silenced
4{
5 use Queueable;
6 
7 // ...
8}

升級 Horizon

升級到新主要版本的 Horizon 時,請務必仔細查看升級指南

執行 Horizon

在您的應用程式 config/horizon.php 設定檔中設定監管者和工作程序後,您可以使用 horizon Artisan 命令啟動 Horizon。此單一命令將啟動目前環境的所有已設定工作程序程序

1php artisan horizon

您可以使用 horizon:pausehorizon:continue Artisan 命令暫停 Horizon 程序並指示其繼續處理任務

1php artisan horizon:pause
2 
3php artisan horizon:continue

您也可以使用 horizon:pause-supervisorhorizon:continue-supervisor Artisan 命令暫停和繼續特定的 Horizon 監管者

1php artisan horizon:pause-supervisor supervisor-1
2 
3php artisan horizon:continue-supervisor supervisor-1

您可以使用 horizon:status Artisan 命令檢查 Horizon 程序的目前狀態

1php artisan horizon:status

您可以使用 horizon:supervisor-status Artisan 命令檢查特定 Horizon 監管者的目前狀態

1php artisan horizon:supervisor-status supervisor-1

您可以使用 horizon:terminate Artisan 命令正常終止 Horizon 程序。目前正在處理的任何任務都將完成,然後 Horizon 將停止執行

1php artisan horizon:terminate

部署 Horizon

當您準備將 Horizon 部署到應用程式的實際伺服器時,您應設定一個程序監控器來監控 php artisan horizon 命令,並在它意外退出時重新啟動它。別擔心,我們將在下面討論如何安裝程序監控器。

在應用程式的部署程序中,您應指示 Horizon 程序終止,以便它將由您的程序監控器重新啟動並接收您的程式碼變更

1php artisan horizon:terminate

安裝 Supervisor

Supervisor 是 Linux 作業系統的程序監控器,如果 horizon 程序停止執行,它將自動重新啟動。若要在 Ubuntu 上安裝 Supervisor,您可以使用以下命令。如果您未使用 Ubuntu,您可以使用作業系統的套件管理器安裝 Supervisor

1sudo apt-get install supervisor

如果您覺得自己設定 Supervisor 令人感到不知所措,請考慮使用 Laravel Cloud,它可以為您的 Laravel 應用程式管理背景程序。

Supervisor 設定

Supervisor 設定檔通常儲存在伺服器的 /etc/supervisor/conf.d 目錄中。在此目錄中,您可以建立任意數量的設定檔,指示 supervisor 應如何監控您的程序。例如,讓我們建立一個 horizon.conf 檔案,以啟動和監控 horizon 程序

1[program:horizon]
2process_name=%(program_name)s
3command=php /home/forge/example.com/artisan horizon
4autostart=true
5autorestart=true
6user=forge
7redirect_stderr=true
8stdout_logfile=/home/forge/example.com/horizon.log
9stopwaitsecs=3600

在定義 Supervisor 設定時,您應確保 stopwaitsecs 的值大於您執行時間最長的任務所消耗的秒數。否則,Supervisor 可能會在任務完成處理之前將其終止。

雖然上面的範例對於基於 Ubuntu 的伺服器有效,但 Supervisor 設定檔的預期位置和檔案副檔名在其他伺服器作業系統之間可能會有所不同。請查閱伺服器的文件以取得更多資訊。

啟動 Supervisor

建立設定檔後,您可以更新 Supervisor 設定並使用以下命令啟動受監控的程序

1sudo supervisorctl reread
2 
3sudo supervisorctl update
4 
5sudo supervisorctl start horizon

有關執行 Supervisor 的更多資訊,請查閱Supervisor 文件

標籤

Horizon 允許您為任務指派「標籤」,包括郵件、廣播事件、通知和佇列事件偵聽器。實際上,Horizon 會根據附加到任務的 Eloquent 模型智慧且自動地標記大多數任務。例如,看看以下任務

1<?php
2 
3namespace App\Jobs;
4 
5use App\Models\Video;
6use Illuminate\Contracts\Queue\ShouldQueue;
7use Illuminate\Foundation\Queue\Queueable;
8 
9class RenderVideo implements ShouldQueue
10{
11 use Queueable;
12 
13 /**
14 * Create a new job instance.
15 */
16 public function __construct(
17 public Video $video,
18 ) {}
19 
20 /**
21 * Execute the job.
22 */
23 public function handle(): void
24 {
25 // ...
26 }
27}

如果此任務以具有 id 屬性為 1App\Models\Video 執行個體加入佇列,它將自動接收標籤 App\Models\Video:1。這是因為 Horizon 將在任務的屬性中搜尋任何 Eloquent 模型。如果找到 Eloquent 模型,Horizon 將使用模型的類別名稱和主鍵智慧地標記任務

1use App\Jobs\RenderVideo;
2use App\Models\Video;
3 
4$video = Video::find(1);
5 
6RenderVideo::dispatch($video);

手動標記任務

如果您想手動定義可佇列物件之一的標籤,您可以在類別上定義 tags 方法

1class RenderVideo implements ShouldQueue
2{
3 /**
4 * Get the tags that should be assigned to the job.
5 *
6 * @return array<int, string>
7 */
8 public function tags(): array
9 {
10 return ['render', 'video:'.$this->video->id];
11 }
12}

手動標記事件偵聽器

當擷取佇列事件偵聽器的標籤時,Horizon 將自動將事件執行個體傳遞給 tags 方法,讓您可以將事件資料新增至標籤

1class SendRenderNotifications implements ShouldQueue
2{
3 /**
4 * Get the tags that should be assigned to the listener.
5 *
6 * @return array<int, string>
7 */
8 public function tags(VideoRendered $event): array
9 {
10 return ['video:'.$event->video->id];
11 }
12}

通知

在設定 Horizon 以傳送 Slack 或 SMS 通知時,您應查看相關通知管道的先決條件

如果您想在其中一個佇列的等待時間過長時收到通知,您可以使用 Horizon::routeMailNotificationsToHorizon::routeSlackNotificationsToHorizon::routeSmsNotificationsTo 方法。您可以從應用程式 App\Providers\HorizonServiceProviderboot 方法中呼叫這些方法

1/**
2 * Bootstrap any application services.
3 */
4public function boot(): void
5{
6 parent::boot();
7 
8 Horizon::routeSmsNotificationsTo('15556667777');
9 Horizon::routeMailNotificationsTo('[email protected]');
10 Horizon::routeSlackNotificationsTo('slack-webhook-url', '#channel');
11}

設定通知等待時間閾值

您可以在應用程式的 config/horizon.php 設定檔中設定多少秒被視為「長時間等待」。此檔案中的 waits 設定選項可讓您控制每個連線/佇列組合的長時間等待閾值。任何未定義的連線/佇列組合都將預設為 60 秒的長時間等待閾值

1'waits' => [
2 'redis:critical' => 30,
3 'redis:default' => 60,
4 'redis:batch' => 120,
5],

指標

Horizon 包含一個指標儀表板,其中提供有關您的任務和佇列等待時間和吞吐量的資訊。為了填充此儀表板,您應設定 Horizon 的 snapshot Artisan 命令每五分鐘在應用程式的 routes/console.php 檔案中執行一次

1use Illuminate\Support\Facades\Schedule;
2 
3Schedule::command('horizon:snapshot')->everyFiveMinutes();

刪除失敗任務

如果您想刪除失敗的任務,您可以使用 horizon:forget 命令。 horizon:forget 命令接受失敗任務的 ID 或 UUID 作為其唯一引數

1php artisan horizon:forget 5

如果您想刪除所有失敗的任務,您可以為 horizon:forget 命令提供 --all 選項

1php artisan horizon:forget --all

清除佇列中的任務

如果您想從應用程式的預設佇列中刪除所有任務,您可以使用 horizon:clear Artisan 命令來執行此操作

1php artisan horizon:clear

您可以提供 queue 選項以從特定佇列中刪除任務

1php artisan horizon:clear --queue=emails