跳至內容

Laravel Horizon

簡介

lightbulb

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

Laravel Horizon 為您以 Laravel 驅動的 Redis 佇列 提供了一個美觀的儀表板和程式碼驅動的配置。Horizon 讓您可以輕鬆監控佇列系統的關鍵指標,例如作業輸送量、執行時間和作業失敗。

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

安裝

exclamation

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

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

composer require laravel/horizon

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

php artisan horizon:install

設定

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

exclamation

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

環境

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

'environments' => [
'production' => [
'supervisor-1' => [
'maxProcesses' => 10,
'balanceMaxShift' => 1,
'balanceCooldown' => 3,
],
],
 
'local' => [
'supervisor-1' => [
'maxProcesses' => 3,
],
],
],

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

'environments' => [
// ...
 
'*' => [
'supervisor-1' => [
'maxProcesses' => 3,
],
],
],

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

exclamation

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

監管者

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

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

維護模式

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

'environments' => [
'production' => [
'supervisor-1' => [
// ...
'force' => true,
],
],
],

預設值

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

平衡策略

與 Laravel 的預設佇列系統不同,Horizon 讓您可以從三種工作程式平衡策略中選擇:simpleautofalsesimple 策略會將傳入的作業平均分配到工作程式程序之間

'balance' => 'simple',

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

使用 auto 策略時,您可以定義 minProcessesmaxProcesses 配置選項,以控制每個佇列的最小程序數,以及 Horizon 應該向上和向下調整的總工作程式程序最大數

'environments' => [
'production' => [
'supervisor-1' => [
'connection' => 'redis',
'queue' => ['default'],
'balance' => 'auto',
'autoScalingStrategy' => 'time',
'minProcesses' => 1,
'maxProcesses' => 10,
'balanceMaxShift' => 1,
'balanceCooldown' => 3,
'tries' => 3,
],
],
],

autoScalingStrategy 配置值決定 Horizon 是否會根據清除佇列所需的總時間(time 策略)或佇列中的作業總數(size 策略)將更多工作程式程序指派給佇列。

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

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

儀表板授權

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

/**
* Register the Horizon gate.
*
* This gate determines who can access Horizon in non-local environments.
*/
protected function gate(): void
{
Gate::define('viewHorizon', function (User $user) {
return in_array($user->email, [
]);
});
}

替代驗證策略

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

靜默作業

有時,您可能對檢視由您的應用程式或第三方套件所派送的某些任務不感興趣。您可以將這些任務靜音,而不是讓它們佔用「已完成任務」清單中的空間。要開始使用,請將任務的類別名稱加入您應用程式的 horizon 設定檔中的 silenced 設定選項。

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

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

use Laravel\Horizon\Contracts\Silenced;
 
class ProcessPodcast implements ShouldQueue, Silenced
{
use Queueable;
 
// ...
}

升級 Horizon

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

執行 Horizon

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

php artisan horizon

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

php artisan horizon:pause
 
php artisan horizon:continue

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

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

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

php artisan horizon:status

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

php artisan horizon:supervisor-status supervisor-1

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

php artisan horizon:terminate

部署 Horizon

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

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

php artisan horizon:terminate

安裝 Supervisor

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

sudo apt-get install supervisor
lightbulb

如果自行設定 Supervisor 聽起來令您感到負擔沉重,請考慮使用 Laravel Forge,它將自動為您的 Laravel 專案安裝和設定 Supervisor。

Supervisor 設定

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

[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

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

exclamation

雖然上面的範例適用於基於 Ubuntu 的伺服器,但 Supervisor 設定檔的預期位置和檔案副檔名可能會因其他伺服器作業系統而異。請查閱您伺服器的文件以獲取更多資訊。

啟動 Supervisor

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

sudo supervisorctl reread
 
sudo supervisorctl update
 
sudo supervisorctl start horizon
lightbulb

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

標籤

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

<?php
 
namespace App\Jobs;
 
use App\Models\Video;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
 
class RenderVideo implements ShouldQueue
{
use Queueable;
 
/**
* Create a new job instance.
*/
public function __construct(
public Video $video,
) {}
 
/**
* Execute the job.
*/
public function handle(): void
{
// ...
}
}

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

use App\Jobs\RenderVideo;
use App\Models\Video;
 
$video = Video::find(1);
 
RenderVideo::dispatch($video);

手動標記任務

如果您想要手動定義可排隊物件的標籤,您可以在類別上定義 tags 方法。

class RenderVideo implements ShouldQueue
{
/**
* Get the tags that should be assigned to the job.
*
* @return array<int, string>
*/
public function tags(): array
{
return ['render', 'video:'.$this->video->id];
}
}

手動標記事件偵聽器

當檢索已排隊的事件偵聽器的標籤時,Horizon 會自動將事件執行個體傳遞給 tags 方法,允許您將事件資料新增至標籤。

class SendRenderNotifications implements ShouldQueue
{
/**
* Get the tags that should be assigned to the listener.
*
* @return array<int, string>
*/
public function tags(VideoRendered $event): array
{
return ['video:'.$event->video->id];
}
}

通知

exclamation

當設定 Horizon 來傳送 Slack 或 SMS 通知時,您應該檢閱相關通知管道的先決條件

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

/**
* Bootstrap any application services.
*/
public function boot(): void
{
parent::boot();
 
Horizon::routeSmsNotificationsTo('15556667777');
Horizon::routeMailNotificationsTo('[email protected]');
Horizon::routeSlackNotificationsTo('slack-webhook-url', '#channel');
}

設定通知等待時間閾值

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

'waits' => [
'redis:critical' => 30,
'redis:default' => 60,
'redis:batch' => 120,
],

指標

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

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

刪除失敗的作業

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

php artisan horizon:forget 5

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

php artisan horizon:forget --all

從佇列中清除作業

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

php artisan horizon:clear

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

php artisan horizon:clear --queue=emails