コンテンツへスキップ

Laravel Horizon

イントロダクション

Laravel Horizonを掘り下げる前に、Laravelの基本的なキューサービスに慣れておく必要があります。HorizonはLaravelのキューに追加機能を加え拡張しているため、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設定ファイルで他のRedis接続に割り当てたり、horizon.php設定ファイルのuseオプションの値として使用したりしてはいけません。

環境

インストール後、最初に慣れるべきHorizonの主要な設定オプションはenvironments設定オプションです。この設定オプションは、アプリケーションが実行される環境の配列であり、各環境のワーカプロセスオプションを定義します。デフォルトでは、このエントリにはproduction環境とlocal環境が含まれています。ただし、必要に応じてさらに環境を追加するのは自由です。

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環境は、3つのワーカプロセスを開始し、各キューに割り当てられるワーカプロセスの数を自動的にバランスするように設定されています。デフォルトのproduction環境は、最大10個のワーカプロセスを開始し、各キューに割り当てられたワーカプロセスの数を自動的にバランスするように設定されています。

horizon設定ファイルのenvironments部分に、Horizonを実行する予定の各環境のエントリが含まれていることを確認する必要があります。

スーパーバイザ

Horizonのデフォルト設定ファイルでわかるように、各環境には1つ以上の「スーパーバイザ」を含めることができます。デフォルトでは、設定ファイルはこのスーパーバイザをsupervisor-1として定義していますが、スーパーバイザには好きな名前を自由につけられます。各スーパーバイザは、基本的にワーカプロセスのグループを「監督」する責任があり、キュー間でワーカプロセスのバランスをとります。

その環境で実行する必要のある新しいワーカプロセスグループを定義したい場合は、特定の環境に追加のスーパーバイザを追加できます。これは、アプリケーションが使用する特定のキューに対して、異なるバランシング戦略またはワーカプロセス数を定義したい場合に選択できます。

メンテナンスモード

アプリケーションがメンテナンスモードの間、Horizon設定ファイル内でスーパーバイザのforceオプションがtrueと定義されていない限り、キューに入れられたジョブはHorizonによって処理されません。

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

デフォルト値

Horizonのデフォルト設定ファイル内に、defaults設定オプションがあります。この設定オプションは、アプリケーションのスーパーバイザのデフォルト値を指定します。スーパーバイザのデフォルト設定値は、各環境のスーパーバイザの設定にマージされるため、スーパーバイザを定義する際の不要な繰り返しを回避できます。

バランシング戦略

Laravelのデフォルトのキューシステムとは異なり、Horizonではsimpleautofalseの3つのワーカバランシング戦略から選択できます。simple戦略は、受信ジョブをワーカプロセス間で均等に分割します。

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がワーカの需要に合わせてどれだけ迅速にスケールするかを決定します。上記の例では、3秒ごとに最大1つの新しいプロセスが作成または破棄されます。アプリケーションのニーズに応じて、これらの値を自由に調整できます。

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ユーザーは「ログイン」する必要がない場合があります。したがって、Laravelに認証を要求させないようにするには、上記のfunction (User $user)クロージャのシグネチャをfunction (User $user = null)に変更する必要があります。

サイレントジョブ

アプリケーションやサードパーティのパッケージによってディスパッチされる特定のジョブの表示に関心がない場合があります。これらのジョブが「完了したジョブ」リストのスペースを占有する代わりに、それらをサイレント(非表示)にできます。開始するには、アプリケーションの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アプリケーションのバックグラウンドプロセスを管理できるLaravel Cloudの使用を検討してください。

Supervisorの設定

Supervisorの設定ファイルは通常、サーバの/etc/supervisor/conf.dディレクトリ内に保存されます。このディレクトリ内に、プロセスをどのように監視するかをSupervisorに指示する設定ファイルをいくつでも作成できます。たとえば、horizonプロセスを開始および監視するhorizon.confファイルを作成してみましょう。

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では、Mailable、ブロードキャストイベント、通知、キュー投入されたイベントリスナなどのジョブに「タグ」を割り当てることができます。実際、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);

手動でのタグ付け

キュー投入可能なオブジェクトの1つに手動でタグを定義したい場合は、そのクラスに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通知を送信する場合は、関連する通知チャネルの前提条件を確認する必要があります。

キューの1つで待機時間が長くなったときに通知を受けたい場合は、Horizon::routeMailNotificationsToHorizon::routeSlackNotificationsTo、およびHorizon::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ファイルで5分ごとに実行するように設定する必要があります。

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

Laravelは最も生産的な方法です
ソフトウェアを構築、デプロイ、監視します。