Laravel Horizon
はじめに
Laravel Horizonを深く掘り下げる前に、Laravelの基本的なキューサービスに精通しておく必要があります。HorizonはLaravelのキューに追加機能を提供しますが、Laravelが提供する基本的なキュー機能に慣れていない場合は、混乱を招く可能性があります。
Laravel Horizon は、Laravel対応のRedisキューのために、美しいダッシュボードとコード駆動型の設定を提供します。Horizonを使用すると、ジョブのスループット、実行時間、ジョブの失敗など、キューシステムの主要なメトリクスを簡単に監視できます。
Horizonを使用する場合、キューワーカーの設定はすべて、シンプルで単一の設定ファイルに保存されます。アプリケーションのワーカー設定をバージョン管理されたファイルで定義することで、アプリケーションのデプロイ時にキューワーカーを簡単にスケールまたは変更できます。
 
インストール
Laravel Horizonを使用するには、Redis をキューの基盤として使用する必要があります。そのため、アプリケーションのconfig/queue.php設定ファイルで、キュー接続がredisに設定されていることを確認する必要があります。
Composerパッケージマネージャーを使用して、プロジェクトにHorizonをインストールできます。
composer require laravel/horizonHorizonをインストールした後、horizon:install Artisanコマンドを使用してアセットを公開します。
php artisan horizon:install設定
Horizonのアセットを公開した後、その主要な設定ファイルはconfig/horizon.phpにあります。この設定ファイルでは、アプリケーションのキューワーカーオプションを設定できます。各設定オプションには目的の説明が含まれているため、このファイルを徹底的に調べてください。
Horizonは内部的にhorizonという名前のRedis接続を使用します。このRedis接続名は予約済みであり、database.php設定ファイルで別のRedis接続に割り当てたり、horizon.php設定ファイルのuseオプションの値として使用したりしないでください。
環境
インストール後、最初に理解しておくべきHorizonの主要な設定オプションは、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 Horizon環境は、3つのワーカープロセスを開始し、各キューに割り当てられたワーカープロセスの数を自動的にバランスするように設定されています。デフォルトのproduction環境は、最大10個のワーカープロセスを開始し、各キューに割り当てられたワーカープロセスの数を自動的にバランスするように設定されています。
horizon設定ファイルのenvironmentsセクションに、Horizonを実行する予定の各環境のエントリが含まれていることを確認する必要があります。
スーパーバイザー
Horizonのデフォルトの設定ファイルに見られるように、各環境には1つ以上の「スーパーバイザー」を含めることができます。デフォルトでは、設定ファイルはこのスーパーバイザーをsupervisor-1として定義していますが、スーパーバイザーの名前は自由に付けることができます。各スーパーバイザーは本質的に、ワーカープロセスのグループを「監視」する役割を担い、キュー間でワーカープロセスをバランスさせる役割を果たします。
特定の環境にスーパーバイザーを追加して、その環境で実行する必要がある新しいワーカープロセスのグループを定義することもできます。これは、アプリケーションで使用される特定のキューに対して、異なるバランス戦略またはワーカープロセスの数を定義したい場合に行うことができます。
メンテナンスモード
アプリケーションがメンテナンスモードになっている間は、Horizon設定ファイル内でスーパーバイザーのforceオプションがtrueとして定義されていない限り、キュージョブはHorizonによって処理されません。
'environments' => [    'production' => [        'supervisor-1' => [            // ...            'force' => true,        ],    ],],デフォルト値
Horizonのデフォルトの設定ファイルでは、defaults設定オプションに注目してください。この設定オプションは、アプリケーションのスーパーバイザーのデフォルト値を指定します。スーパーバイザーのデフォルトの設定値は、各環境のスーパーバイザーの設定にマージされるため、スーパーバイザーを定義する際に不要な繰り返しを避けることができます。
バランス戦略
Laravelのデフォルトのキューシステムとは異なり、Horizonでは、simple、auto、falseの3つのワーカーバランス戦略から選択できます。simple戦略は、着信ジョブをワーカープロセス間で均等に分割します。
'balance' => 'simple',設定ファイルのデフォルトであるauto戦略は、キューの現在のワークロードに基づいて、キューあたりのワーカープロセスの数を調整します。たとえば、notificationsキューに1,000件の保留中のジョブがあり、renderキューが空の場合、Horizonはnotificationsキューが空になるまで、notificationsキューにより多くのワーカーを割り当てます。
auto戦略を使用する場合、minProcessesとmaxProcesses設定オプションを定義して、キューあたりの最小プロセス数と、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 戦略) に基づいて、キューにワーカープロセスを追加するかどうかを決定します。
balanceMaxShift と balanceCooldown 設定値は、Horizon がワーカーの需要を満たすためにスケールする速度を決定します。上記の例では、3 秒ごとに最大で 1 つの新しいプロセスが作成または破棄されます。アプリケーションのニーズに応じて、これらの値を必要に応じて調整できます。
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 ユーザーは「ログイン」する必要がない場合があります。したがって、Laravel に認証を要求させないようにするには、上記の function (User $user) クロージャのシグネチャを function (User $user = null) に変更する必要があります。
サイレントジョブ
アプリケーションまたはサードパーティパッケージによってディスパッチされた特定のジョブの表示に興味がない場合があります。「完了したジョブ」リストにこれらのジョブが表示されないようにするには、サイレント化できます。開始するには、アプリケーションの 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 horizonhorizon:pause と horizon:continue Artisan コマンドを使用して、Horizon プロセスを一時停止し、ジョブの処理を再開するように指示できます。
php artisan horizon:pause php artisan horizon:continuehorizon:pause-supervisor と horizon:continue-supervisor Artisan コマンドを使用して、特定の Horizon スーパーバイザー を一時停止および再開することもできます。
php artisan horizon:pause-supervisor supervisor-1 php artisan horizon:continue-supervisor supervisor-1horizon:status Artisan コマンドを使用して、Horizon プロセスの現在の状態を確認できます。
php artisan horizon:statushorizon:supervisor-status Artisan コマンドを使用して、特定の Horizon スーパーバイザー の現在の状態を確認できます。
php artisan horizon:supervisor-status supervisor-1horizon:terminate Artisan コマンドを使用して、Horizon プロセスを正常に終了できます。現在処理中のジョブは完了し、その後 Horizon は実行を停止します。
php artisan horizon:terminateHorizonのデプロイ
Horizon をアプリケーションの実際のサーバーにデプロイする準備ができたら、php artisan horizon コマンドを監視し、予期せず終了した場合に再起動するプロセスモニターを設定する必要があります。心配しないでください。以下でプロセスモニターのインストール方法について説明します。
アプリケーションのデプロイプロセス中に、Horizon プロセスを終了するように指示する必要があります。これにより、プロセスモニターによって再起動され、コードの変更が反映されます。
php artisan horizon:terminateSupervisor のインストール
Supervisor は Linux オペレーティングシステムのプロセスモニターであり、horizon プロセスが実行を停止した場合に自動的に再起動します。Ubuntu に Supervisor をインストールするには、次のコマンドを使用できます。Ubuntu を使用していない場合は、オペレーティングシステムのパッケージマネージャーを使用して Supervisor をインストールできる可能性があります。
sudo apt-get install supervisorSupervisor の自身による設定が困難な場合は、Laravel Forge を使用することを検討してください。Laravel Forge は、Laravel プロジェクトの Supervisor を自動的にインストールして設定します。
Supervisor の設定
Supervisor の設定ファイルは、通常、サーバーの /etc/supervisor/conf.d ディレクトリに保存されます。このディレクトリでは、プロセスを監視する方法を Supervisor に指示する設定ファイルをいくつでも作成できます。たとえば、horizon プロセスを開始して監視する horizon.conf ファイルを作成してみましょう。
[program:horizon]process_name=%(program_name)scommand=php /home/forge/example.com/artisan horizonautostart=trueautorestart=trueuser=forgeredirect_stderr=truestdout_logfile=/home/forge/example.com/horizon.logstopwaitsecs=3600Supervisor の設定を定義する際には、stopwaitsecs の値が、最も長く実行されるジョブによって消費される秒数よりも大きくなるようにする必要があります。そうでない場合、Supervisor はジョブが処理を完了する前にジョブを強制終了する可能性があります。
上記の例は Ubuntu ベースのサーバーで有効ですが、Supervisor 設定ファイルの場所とファイル拡張子は、他のサーバーオペレーティングシステムによって異なる場合があります。詳細については、サーバーのドキュメントを参照してください。
Supervisor の開始
設定ファイルを作成したら、次のコマンドを使用して Supervisor の設定を更新し、監視対象のプロセスを開始できます。
sudo supervisorctl reread sudo supervisorctl update sudo supervisorctl start horizonSupervisor の実行の詳細については、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 属性が 1 の App\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];    }}通知
Slack または SMS 通知を送信するように Horizon を設定する際には、関連する通知チャネルの前提条件 を確認する必要があります。
キューのいずれかの待機時間が長い場合に通知を受け取る場合は、Horizon::routeMailNotificationsTo、Horizon::routeSlackNotificationsTo、Horizon::routeSmsNotificationsTo メソッドを使用できます。これらのメソッドは、アプリケーションの App\Providers\HorizonServiceProvider の boot メソッドから呼び出すことができます。
/** * Bootstrap any application services. */public function boot(): void{    parent::boot();     Horizon::routeSmsNotificationsTo('15556667777');    Horizon::routeSlackNotificationsTo('slack-webhook-url', '#channel');}通知待機時間しきい値の設定
アプリケーションの config/horizon.php 設定ファイル内で、「長い待機時間」と見なされる秒数を設定できます。このファイル内の waits 設定オプションを使用すると、接続/キューの組み合わせごとに長い待機時間しきい値を制御できます。未定義の接続/キューの組み合わせは、デフォルトで 60 秒の長い待機時間しきい値になります。
'waits' => [    'redis:critical' => 30,    'redis:default' => 60,    'redis:batch' => 120,],メトリクス
Horizon には、ジョブとキューの待機時間とスループットに関する情報を提供するメトリックスダッシュボードが含まれています。このダッシュボードにデータを入力するには、アプリケーションの routes/console.php ファイルで Horizon の snapshot Artisan コマンドが 5 分ごとに実行されるように設定する必要があります。
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