イントロダクションIntroduction
Webアプリケーションの構築中に、アップロードされたCSVファイルの解析や保存など、通常のWebリクエスト中に実行するのでは時間がかかりすぎるタスクが発生する場合があります。幸運なことに、Laravelを使用すると、バックグラウンドで処理したい仕事をキューへ投入するジョブクラスが簡単に作成できます。時間のかかるタスクをキューに移動することで、アプリケーションはWebリクエストに驚異的な速度でレスポンスし、顧客により良いユーザーエクスペリエンスを提供できます。While building your web application, you may have some tasks, such as parsing and storing an uploaded CSV file, that take too long to perform during a typical web request. Thankfully, Laravel allows you to easily create queued jobs that may be processed in the background. By moving time intensive tasks to a queue, your application can respond to web requests with blazing speed and provide a better user experience to your customers.
Laravelキューは異なったキューバックエンド間に統一したキューのAPIを提供します。Amazon SQS、Redis、もしくはリレーショナルデータベースでさえ使えます。Laravel queues provide a unified queueing API across a variety of different queue backends, such as Amazon SQS[https://aws.amazon.com/sqs/], Redis[https://redis.io], or even a relational database.
Laravelのキュー設定オプションは、アプリケーションのconfig/queue.php
設定ファイルへ保存します。このファイルには、データベース、Amazon SQS, Redis, Beanstalkdドライバを含む、フレームワークが用意しているキュードライバの各接続設定が含まれています。また、キューに投入されたジョブを破棄する null
キュードライバも含まれています。Laravel's queue configuration options are stored in your application's config/queue.php
configuration file. In this file, you will find connection configurations for each of the queue drivers that are included with the framework, including the database, Amazon SQS[https://aws.amazon.com/sqs/], Redis[https://redis.io], and Beanstalkd[https://beanstalkd.github.io/] drivers, as well as a synchronous driver that will execute jobs immediately (for use during local development). A null
queue driver is also included which discards queued jobs.
Horizonドキュメントを確認してください。[!NOTE]
Note: Laravelは、Redisを利用したキュー用の美しいダッシュボードと設定システムであるHorizonも提供しています。詳細は、完全な
Laravel now offers Horizon, a beautiful dashboard and configuration system for your Redis powered queues. Check out the full Horizon documentation[/docs/{{version}}/horizon] for more information.
接続 対 キューConnections vs. Queues
Laravelキューを使い始める前に、「接続」と「キュー」の違いを理解することが重要です。config/queue.php
設定ファイルには、connections
設定配列があります。このオプションは、Amazon SQS、Beanstalk、Redisなどのバックエンドキューサービスへの接続を定義します。ただし、特定のキュー接続には複数の「キュー」があり、キューに投入するジョブの異なるスタックまたはパイルと考えられます。Before getting started with Laravel queues, it is important to understand the distinction between "connections" and "queues". In your config/queue.php
configuration file, there is a connections
configuration array. This option defines the connections to backend queue services such as Amazon SQS, Beanstalk, or Redis. However, any given queue connection may have multiple "queues" which may be thought of as different stacks or piles of queued jobs.
queue
設定ファイルの各接続設定例にはqueue
属性が含まれていることに注意してください。これは、ジョブが特定の接続に送信されるときにジョブがディスパッチされるデフォルトのキューです。つまり、ディスパッチ先のキューを明示的に定義せずにジョブをディスパッチすると、ジョブは接続設定のqueue
属性で定義されているキューへ配置されます。Note that each connection configuration example in the queue
configuration file contains a queue
attribute. This is the default queue that jobs will be dispatched to when they are sent to a given connection. In other words, if you dispatch a job without explicitly defining which queue it should be dispatched to, the job will be placed on the queue that is defined in the queue
attribute of the connection configuration:
use App\Jobs\ProcessPodcast;
// このジョブは、デフォルト接続のデフォルトキューに送信される
ProcessPodcast::dispatch();
// このジョブは、デフォルトの接続の"emails"キューに送信される
ProcessPodcast::dispatch()->onQueue('emails');
あるアプリケーションでは、ジョブを複数のキューにプッシュする必要がなく、代わりに1つの単純なキューを使用するのが好まれるでしょう。しかし、ジョブを複数のキューにプッシュすることで、ジョブの処理方法に優先順位を付けたりセグメント化したりしたいアプリケーションで特に役立ちます。Laravelキューワーカは、優先度で処理するキューを指定できるためです。たとえば、ジョブを「高high
」キューにプッシュする場合、より高い処理優先度を与えたワーカを実行します。Some applications may not need to ever push jobs onto multiple queues, instead preferring to have one simple queue. However, pushing jobs to multiple queues can be especially useful for applications that wish to prioritize or segment how jobs are processed, since the Laravel queue worker allows you to specify which queues it should process by priority. For example, if you push jobs to a high
queue, you may run a worker that gives them higher processing priority:
php artisan queue:work --queue=high,default
ドライバの注意と事前要件Driver Notes and Prerequisites
データベースDatabase
database
キュードライバを使用するには、ジョブを保持するデータベーステーブルが必要です。通常、これはLaravelのデフォルト0001_01_000002_create_jobs_table.php
データベースマイグレーションに含まれていますが、アプリケーションにこのマイグレーションが含まれていない場合は、make:queue-table
Artisanコマンドを使用して作成できます。In order to use the database
queue driver, you will need a database table to hold the jobs. Typically, this is included in Laravel's default 0001_01_01_000002_create_jobs_table.php
database migration[/docs/{{version}}/migrations]; however, if your application does not contain this migration, you may use the make:queue-table
Artisan command to create it:
php artisan make:queue-table
php artisan migrate
RedisRedis
redis
キュードライバを使用するには、config/database.php
設定ファイルでRedisデータベース接続を設定する必要があります。In order to use the redis
queue driver, you should configure a Redis database connection in your config/database.php
configuration file.
Warning!
redis
キュードライバでは、serializer
とcompression
Redisオプションをサポートしていません。[!WARNING]
Theserializer
andcompression
Redis options are not supported by theredis
queue driver.
RedisクラスタRedis Cluster
Redisキュー接続でRedisクラスタを使用する場合、キュー名にキーハッシュタグを含める必要があります。これは、特定のキューのすべてのRedisキーが同じハッシュスロットに配置されるようにするために必要です。If your Redis queue connection uses a Redis Cluster, your queue names must contain a key hash tag[https://redis.io/docs/reference/cluster-spec/#hash-tags]. This is required in order to ensure all of the Redis keys for a given queue are placed into the same hash slot:
'redis' => [
'driver' => 'redis',
'connection' => env('REDIS_QUEUE_CONNECTION', 'default'),
'queue' => env('REDIS_QUEUE', '{default}'),
'retry_after' => env('REDIS_QUEUE_RETRY_AFTER', 90),
'block_for' => null,
'after_commit' => false,
],
ブロッキングBlocking
Redisキューを使用する場合は、block_for
設定オプションを使用して、ワーカループを反復処理し、Redisデータベースを再ポーリングする前に、ドライバがジョブが使用可能になるまで待機する時間を指定します。When using the Redis queue, you may use the block_for
configuration option to specify how long the driver should wait for a job to become available before iterating through the worker loop and re-polling the Redis database.
キューの負荷に基づいてこの値を調整する方が、Redisデータベースを継続的にポーリングして新しいジョブを探すよりも効率的です。たとえば、値を「5」に設定して、ジョブが使用可能になるのを待つまで、ドライバが5秒間ブロックする必要があることを示すことができます。Adjusting this value based on your queue load can be more efficient than continually polling the Redis database for new jobs. For instance, you may set the value to 5
to indicate that the driver should block for five seconds while waiting for a job to become available:
'redis' => [
'driver' => 'redis',
'connection' => env('REDIS_QUEUE_CONNECTION', 'default'),
'queue' => env('REDIS_QUEUE', 'default'),
'retry_after' => env('REDIS_QUEUE_RETRY_AFTER', 90),
'block_for' => 5,
'after_commit' => false,
],
Warning!
block_for
を0
に設定すると、ジョブが使用可能になるまでキューワーカが無期限にブロックします。これにより、次のジョブが処理されるまで、SIGTERM
などのシグナルが処理されなくなります。[!WARNING]
Settingblock_for
to0
will cause queue workers to block indefinitely until a job is available. This will also prevent signals such asSIGTERM
from being handled until the next job has been processed.
その他のドライバの事前要件Other Driver Prerequisites
以下にリストしたキュードライバには、次の依存パッケージが必要です。これらの依存パッケージは、Composerパッケージマネージャを介してインストールできます。The following dependencies are needed for the listed queue drivers. These dependencies may be installed via the Composer package manager:
- Amazon SQS:
aws/aws-sdk-php ~3.0
Amazon SQS:aws/aws-sdk-php ~3.0
- Beanstalkd:
pda/pheanstalk ~5.0
Beanstalkd:pda/pheanstalk ~5.0
- Redis:
predis/predis ~2.0
or phpredis PHP extensionRedis:predis/predis ~2.0
or phpredis PHP extension - MongoDB:
mongodb/laravel-mongodb
MongoDB[https://www.mongodb.com/docs/drivers/php/laravel-mongodb/current/queues/]:mongodb/laravel-mongodb
ジョブの生成Creating Jobs
ジョブクラスの生成Generating Job Classes
デフォルトでは、アプリケーションのすべてのqueueableジョブは、app/Jobs
ディレクトリに保存します。app/Jobs
ディレクトリが存在しない場合でも、make:job
Artisanコマンドを実行すると作成されます。By default, all of the queueable jobs for your application are stored in the app/Jobs
directory. If the app/Jobs
directory doesn't exist, it will be created when you run the make:job
Artisan command:
php artisan make:job ProcessPodcast
生成されたクラスはIlluminate\Contracts\Queue\ShouldQueue
インターフェイスを実装し、そのジョブをキューに投入する必要があり、非同期で実行することをLaravelに示します。The generated class will implement the Illuminate\Contracts\Queue\ShouldQueue
interface, indicating to Laravel that the job should be pushed onto the queue to run asynchronously.
スタブのリソース公開を使用してカスタマイズできます[!NOTE]
Note: ジョブスタブは
Job stubs may be customized using stub publishing[/docs/{{version}}/artisan#stub-customization].
クラスの構造Class Structure
ジョブクラスは非常に単純で、ジョブがキューにより処理されるときに通常呼び出すhandle
メソッドのみを持ちます。手始めに、ジョブクラスの例を見てみましょう。この例では、ポッドキャスト公開サービスを管理していて、アップロードされたポッドキャストファイルを公開する前に必要な処理があるのだと仮定してください。Job classes are very simple, normally containing only a handle
method that is invoked when the job is processed by the queue. To get started, let's take a look at an example job class. In this example, we'll pretend we manage a podcast publishing service and need to process the uploaded podcast files before they are published:
<?php
namespace App\Jobs;
use App\Models\Podcast;
use App\Services\AudioProcessor;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
class ProcessPodcast implements ShouldQueue
{
use Queueable;
/**
* 新しいジョブインスタンスの生成
*/
public function __construct(
public Podcast $podcast,
) {}
/**
* ジョブの実行
*/
public function handle(AudioProcessor $processor): void
{
// アップロードされたポッドキャストを処理…
}
}
この例では、Eloquentモデルをキュー投入するジョブのコンストラクタへ直接渡すことができたことに注意してください。ジョブが使用しているQueueable
トレイトにより、Eloquentモデルとそれらのロード済みリレーションは、ジョブの処理時に正常にシリアル化および非シリアル化されます。In this example, note that we were able to pass an Eloquent model[/docs/{{version}}/eloquent] directly into the queued job's constructor. Because of the Queueable
trait that the job is using, Eloquent models and their loaded relationships will be gracefully serialized and unserialized when the job is processing.
キュー投入するジョブがコンストラクタでEloquentモデルを受け入れる場合、モデルの識別子のみがキューにシリアル化されます。ジョブが実際に処理されると、キューシステムは、完全なモデルインスタンスとそのロード済みリレーションをデータベースから自動的に再取得します。モデルのシリアル化に対するこのアプローチにより、はるかに小さなジョブペイロードをキュードライバに送信できます。If your queued job accepts an Eloquent model in its constructor, only the identifier for the model will be serialized onto the queue. When the job is actually handled, the queue system will automatically re-retrieve the full model instance and its loaded relationships from the database. This approach to model serialization allows for much smaller job payloads to be sent to your queue driver.
handle
メソッドの依存注入handle
Method Dependency Injection
handle
メソッドは、ジョブがキューにより処理されるときに呼び出されます。そのジョブのhandle
メソッドで依存関係をタイプヒントできることに注意してください。Laravelサービスコンテナは、これらの依存関係を自動的に依存注入します。The handle
method is invoked when the job is processed by the queue. Note that we are able to type-hint dependencies on the handle
method of the job. The Laravel service container[/docs/{{version}}/container] automatically injects these dependencies.
コンテナが依存関係をhandle
メソッドへ依存注入する方法を完全に制御したい場合は、コンテナのbindMethod
メソッドを使用します。bindMethod
メソッドは、ジョブとコンテナを受け取るコールバックを受け入れます。コールバック内で、必要に応じてhandle
メソッドを自由に呼び出すことができます。通常、このメソッドは、App\Providers\AppServiceProvider
サービスプロバイダのboot
メソッドから呼び出す必要があります。If you would like to take total control over how the container injects dependencies into the handle
method, you may use the container's bindMethod
method. The bindMethod
method accepts a callback which receives the job and the container. Within the callback, you are free to invoke the handle
method however you wish. Typically, you should call this method from the boot
method of your App\Providers\AppServiceProvider
service provider[/docs/{{version}}/providers]:
use App\Jobs\ProcessPodcast;
use App\Services\AudioProcessor;
use Illuminate\Contracts\Foundation\Application;
$this->app->bindMethod([ProcessPodcast::class, 'handle'], function (ProcessPodcast $job, Application $app) {
return $job->handle($app->make(AudioProcessor::class));
});
Warning! 素の画像の内容などのバイナリデータは、キュー投入するジョブへ渡す前に、
base64_encode
関数を介して渡す必要があります。そうしないと、ジョブがキューに配置されたときにJSONへ適切にシリアル化されない可能性があります。[!WARNING]
Binary data, such as raw image contents, should be passed through thebase64_encode
function before being passed to a queued job. Otherwise, the job may not properly serialize to JSON when being placed on the queue.
リレーションのキュー投入Queued Relationships
ロード済みのEloquentモデルリレーションはすべて、ジョブをキューに投入したときにシリアライズされるため、シリアライズしたジョブの文字列は非常に大きくなることがあります。さらに、ジョブがデシリアライズされ、モデルのリレーションがデータベースから再取得されるときには、こうした情報を完全に取得します。ジョブキューの処理中にモデルをシリアライズする前に適用されていたリレーションの制約は、そのジョブをデシリアライズするときに適用されません。したがって、特定のリレーションシップのサブセットを操作したい場合は、キューイングするジョブ内でそのリレーションを再制約する必要があります。Because all loaded Eloquent model relationships also get serialized when a job is queued, the serialized job string can sometimes become quite large. Furthermore, when a job is deserialized and model relationships are re-retrieved from the database, they will be retrieved in their entirety. Any previous relationship constraints that were applied before the model was serialized during the job queueing process will not be applied when the job is deserialized. Therefore, if you wish to work with a subset of a given relationship, you should re-constrain that relationship within your queued job.
もしくは、リレーションをシリアライズされないようにするため、プロパティ値を設定するときにモデルのwithoutRelations
メソッドを呼び出すこともできます。このメソッドは、ロード済みのリレーションシップを除いたモデルのインスタンスを返します。Or, to prevent relations from being serialized, you can call the withoutRelations
method on the model when setting a property value. This method will return an instance of the model without its loaded relationships:
/**
* 新しいジョブインスタンスの生成
*/
public function __construct(
Podcast $podcast,
) {
$this->podcast = $podcast->withoutRelations();
}
PHPのコンストラクタ・プロパティ・プロモーションを使用していて、あるEloquentモデルでリレーションをシリアライズしないことを指定したい場合は、WithoutRelations
属性を使用します:If you are using PHP constructor property promotion and would like to indicate that an Eloquent model should not have its relations serialized, you may use the WithoutRelations
attribute:
use Illuminate\Queue\Attributes\WithoutRelations;
/**
* 新しいジョブインスタンスの生成
*/
public function __construct(
#[WithoutRelations]
public Podcast $podcast,
) {}
ジョブが単一モデルの代わりに、Eloquentモデルのコレクションまたは配列を受け取った場合、そのコレクション内のモデルでは、ジョブがデシリアライズされて実行されるときにそれらのリレーションは復元されません。これは、大量のモデルを扱うジョブで過剰なリソース使用を防ぐためです。If a job receives a collection or array of Eloquent models instead of a single model, the models within that collection will not have their relationships restored when the job is deserialized and executed. This is to prevent excessive resource usage on jobs that deal with large numbers of models.
一意なジョブUnique Jobs
ロックをサポートするキャッシュドライバが必要です。現在、
Warning! 一意なジョブには、memcached
、redis
、dynamodb
、database
、file
、array
キャッシュドライバはアトミックロックをサポートしています。また、一意なジョブの制約は、バッチ内のジョブには適用されません。[!WARNING]
Unique jobs require a cache driver that supports locks[/docs/{{version}}/cache#atomic-locks]. Currently, thememcached
,redis
,dynamodb
,database
,file
, andarray
cache drivers support atomic locks. In addition, unique job constraints do not apply to jobs within batches.
特定のジョブの1つのインスタンスのみを確実にキューで常に存在させたい場合があります。これを行うには、ジョブクラスにShouldBeUnique
インターフェイスを実装します。このインターフェイスでは、クラスへ追加のメソッドを定義する必要はありません。Sometimes, you may want to ensure that only one instance of a specific job is on the queue at any point in time. You may do so by implementing the ShouldBeUnique
interface on your job class. This interface does not require you to define any additional methods on your class:
<?php
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Contracts\Queue\ShouldBeUnique;
class UpdateSearchIndex implements ShouldQueue, ShouldBeUnique
{
...
}
上記の例では、UpdateSearchIndex
ジョブは一意になります。したがって、ジョブの別のインスタンスがすでにキューにあり、処理が完了していない場合、ジョブはディスパッチされません。In the example above, the UpdateSearchIndex
job is unique. So, the job will not be dispatched if another instance of the job is already on the queue and has not finished processing.
場合によっては、ジョブを一意にする特定の「キー」を定義したり、それを超えるとジョブが一意でなくなるタイムアウトを指定したりすることができます。これを行うには、ジョブクラスでuniqueId
およびuniqueFor
プロパティまたはメソッドを定義します。In certain cases, you may want to define a specific "key" that makes the job unique or you may want to specify a timeout beyond which the job no longer stays unique. To accomplish this, you may define uniqueId
and uniqueFor
properties or methods on your job class:
<?php
use App\Models\Product;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Contracts\Queue\ShouldBeUnique;
class UpdateSearchIndex implements ShouldQueue, ShouldBeUnique
{
/**
* 製品インスタンス
*
* @var \App\Product
*/
public $product;
/**
* ジョブの一意のロックが解放されるまでの秒数
*
* @var int
*/
public $uniqueFor = 3600;
/**
* ジョブの一意IDの取得
*/
public function uniqueId(): string
{
return $this->product->id;
}
}
上記の例では、UpdateSearchIndex
ジョブは製品IDによって一意になります。したがって、同じ製品IDを持つジョブの新しいディスパッチは、既存のジョブが処理を完了するまで無視されます。さらに、既存のジョブが1時間以内に処理されない場合、一意のロックが解放され、同じ一意のキーを持つ別のジョブをキューにディスパッチできます。In the example above, the UpdateSearchIndex
job is unique by a product ID. So, any new dispatches of the job with the same product ID will be ignored until the existing job has completed processing. In addition, if the existing job is not processed within one hour, the unique lock will be released and another job with the same unique key can be dispatched to the queue.
[!WARNING]
Warning! アプリケーションで複数のウェブサーバやコンテナからジョブをディスパッチする場合、すべてのサーバが同じセントラルキャッシュサーバと通信していることを確認し、Laravelがジョブをユニークであるかを正確に判定できるようにする必要があります。
If your application dispatches jobs from multiple web servers or containers, you should ensure that all of your servers are communicating with the same central cache server so that Laravel can accurately determine if a job is unique.
処理が開始されるまでジョブを一意に保つKeeping Jobs Unique Until Processing Begins
ジョブが処理を完了した後、または再試行にすべて失敗した後、一意のジョブは「ロック解除」されるのがデフォルト動作です。ただし、ジョブが処理される直前にロックを解除したい場合もあるでしょう。これを実現するには、ジョブで「ShouldBeUnique
契約ではなくShouldBeUniqueUntilProcessing
契約を実装する必要があります。By default, unique jobs are "unlocked" after a job completes processing or fails all of its retry attempts. However, there may be situations where you would like your job to unlock immediately before it is processed. To accomplish this, your job should implement the ShouldBeUniqueUntilProcessing
contract instead of the ShouldBeUnique
contract:
<?php
use App\Models\Product;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Contracts\Queue\ShouldBeUniqueUntilProcessing;
class UpdateSearchIndex implements ShouldQueue, ShouldBeUniqueUntilProcessing
{
// ...
}
一意なジョブロックUnique Job Locks
ShouldBeUnique
ジョブがディスパッチされると、裏でLaravelはuniqueId
キーを使用してロックを取得しようとします。ロックが取得されていない場合、ジョブはディスパッチされません。このロックは、ジョブが処理を完了するか、再試行にすべて失敗すると解放されます。Laravelはデフォルトのキャッシュドライバを使用してこのロックを取得するのがデフォルト動作です。ただし、ロックを取得するために別のドライバを使用する場合は、使用するキャッシュドライバを返すuniqueVia
メソッドを定義します。Behind the scenes, when a ShouldBeUnique
job is dispatched, Laravel attempts to acquire a lock[/docs/{{version}}/cache#atomic-locks] with the uniqueId
key. If the lock is not acquired, the job is not dispatched. This lock is released when the job completes processing or fails all of its retry attempts. By default, Laravel will use the default cache driver to obtain this lock. However, if you wish to use another driver for acquiring the lock, you may define a uniqueVia
method that returns the cache driver that should be used:
use Illuminate\Contracts\Cache\Repository;
use Illuminate\Support\Facades\Cache;
class UpdateSearchIndex implements ShouldQueue, ShouldBeUnique
{
...
/**
* 一意のジョブロックのキャッシュドライバを取得
*/
public function uniqueVia(): Repository
{
return Cache::driver('redis');
}
}
Note: ジョブの同時処理を制限するだけでよい場合は、代わりに
WithoutOverlapping
ジョブミドルウェアを使用してください。[!NOTE]
If you only need to limit the concurrent processing of a job, use theWithoutOverlapping
[/docs/{{version}}/queues#preventing-job-overlaps] job middleware instead.
ジョブの暗号化Encrypted Jobs
Laravelでは、暗号化により、ジョブのデータのプライバシーと完全性を確保できます。これを始めるには、ジョブクラスへShouldBeEncrypted
インターフェイスを追加するだけです。このインターフェイスがクラスへ追加されると、Laravelはジョブをキューにプッシュする前に自動的に暗号化します。Laravel allows you to ensure the privacy and integrity of a job's data via encryption[/docs/{{version}}/encryption]. To get started, simply add the ShouldBeEncrypted
interface to the job class. Once this interface has been added to the class, Laravel will automatically encrypt your job before pushing it onto a queue:
<?php
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use Illuminate\Contracts\Queue\ShouldQueue;
class UpdateSearchIndex implements ShouldQueue, ShouldBeEncrypted
{
// ...
}
ジョブミドルウェアJob Middleware
ジョブミドルウェアを使用すると、キュー投入するジョブの実行にカスタムロジックをラップして、ジョブ自体の定型コードを減らせます。例として、LaravelのRedisレート制限機能を利用して、5秒ごとに1つのジョブのみを処理できるようにする次の「handle」メソッドを考えてみましょう。Job middleware allow you to wrap custom logic around the execution of queued jobs, reducing boilerplate in the jobs themselves. For example, consider the following handle
method which leverages Laravel's Redis rate limiting features to allow only one job to process every five seconds:
use Illuminate\Support\Facades\Redis;
/**
* ジョブの実行
*/
public function handle(): void
{
Redis::throttle('key')->block(0)->allow(1)->every(5)->then(function () {
info('Lock obtained...');
// ジョブを処理…
}, function () {
// ロックの取得失敗
return $this->release(5);
});
}
このコードは有効ですが、handle
メソッドの実装は、Redisのレート制限ロジックが散らかっているため、ノイズが多くなります。さらに、このレート制限ロジックは、レート制限する他のジョブでも重複。While this code is valid, the implementation of the handle
method becomes noisy since it is cluttered with Redis rate limiting logic. In addition, this rate limiting logic must be duplicated for any other jobs that we want to rate limit.
handleメソッドでレート制限を行う代わりに、レート制限を処理するジョブミドルウェアを定義できます。Laravelにはジョブミドルウェアのデフォルトの場所が存在ないため、アプリケーションのどこにでもジョブミドルウェアを配置できます。この例では、ミドルウェアをapp/Jobs/Middleware
ディレクトリに配置します。Instead of rate limiting in the handle method, we could define a job middleware that handles rate limiting. Laravel does not have a default location for job middleware, so you are welcome to place job middleware anywhere in your application. In this example, we will place the middleware in an app/Jobs/Middleware
directory:
<?php
namespace App\Jobs\Middleware;
use Closure;
use Illuminate\Support\Facades\Redis;
class RateLimited
{
/**
* キュー投入したジョブの処理
*
* @param \Closure(object): void $next
*/
public function handle(object $job, Closure $next): void
{
Redis::throttle('key')
->block(0)->allow(1)->every(5)
->then(function () use ($job, $next) {
// ロック取得
$next($job);
}, function () use ($job) {
// ロックの取得失敗
$job->release(5);
});
}
}
ご覧のとおり、routeミドルウェアのように、ジョブミドルウェアは処理中のジョブと、ジョブの処理を続行するために呼び出す必要のあるコールバックを受け取ります。As you can see, like route middleware[/docs/{{version}}/middleware], job middleware receive the job being processed and a callback that should be invoked to continue processing the job.
ジョブミドルウェアを作成したら、ジョブのmiddleware
メソッドから返すことで、ジョブにアタッチできます。このメソッドは、make:job
Artisanコマンドによってスカフォールドされたジョブには存在しないため、手作業でジョブクラスへ追加する必要があります。After creating job middleware, they may be attached to a job by returning them from the job's middleware
method. This method does not exist on jobs scaffolded by the make:job
Artisan command, so you will need to manually add it to your job class:
use App\Jobs\Middleware\RateLimited;
/**
* このジョブを通過させるミドルウェアを取得
*
* @return array<int, object>
*/
public function middleware(): array
{
return [new RateLimited];
}
[!NOTE]
Note: Jobミドルウェアは、Queueableなイベントリスナ、Mailable、通知にも割り当てできます。
Job middleware can also be assigned to queueable event listeners, mailables, and notifications.
レート制限Rate Limiting
独自のレート制限ジョブミドルウェアを作成する方法を示したばかりですが、実際には、Laravelはレート制限ジョブに利用できるレート制限ミドルウェアが含まれています。ルートのレートリミッタと同様に、ジョブのレートリミッタはRateLimiter
ファサードのfor
メソッドを使用して定義します。Although we just demonstrated how to write your own rate limiting job middleware, Laravel actually includes a rate limiting middleware that you may utilize to rate limit jobs. Like route rate limiters[/docs/{{version}}/routing#defining-rate-limiters], job rate limiters are defined using the RateLimiter
facade's for
method.
たとえば、プレミアム顧客には制限を課さずに、一般ユーザーには1時間に1回データをバックアップできるようにしたい場合があると思います。これを実現するには、AppServiceProvider
のboot
メソッドでRateLimiter
を定義します。For example, you may wish to allow users to backup their data once per hour while imposing no such limit on premium customers. To accomplish this, you may define a RateLimiter
in the boot
method of your AppServiceProvider
:
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;
/**
* 全アプリケーションサービスの初期起動処理
*/
public function boot(): void
{
RateLimiter::for('backups', function (object $job) {
return $job->user->vipCustomer()
? Limit::none()
: Limit::perHour(1)->by($job->user->id);
});
}
上記の例では、1時間ごとのレート制限を定義しました。しかし、perMinute
メソッドを使用して、分に基づいたレート制限も簡単に定義できます。さらに、レート制限のby
メソッドへ任意の値を渡せます。この値は、顧客ごとにレート制限をセグメント化するために最もよく使用されます。In the example above, we defined an hourly rate limit; however, you may easily define a rate limit based on minutes using the perMinute
method. In addition, you may pass any value you wish to the by
method of the rate limit; however, this value is most often used to segment rate limits by customer:
return Limit::perMinute(50)->by($job->user->id);
レート制限を定義したら、Illuminate\Queue\Middleware\RateLimited
ミドルウェアを使用してレートリミッターをジョブにアタッチできます。ジョブがレート制限を超えるたびに、このミドルウェアは、レート制限期間に基づいて適切な遅延でジョブをキューに戻します。Once you have defined your rate limit, you may attach the rate limiter to your job using the Illuminate\Queue\Middleware\RateLimited
middleware. Each time the job exceeds the rate limit, this middleware will release the job back to the queue with an appropriate delay based on the rate limit duration.
use Illuminate\Queue\Middleware\RateLimited;
/**
* このジョブを通過させるミドルウェアを取得
*
* @return array<int, object>
*/
public function middleware(): array
{
return [new RateLimited('backups')];
}
レート制限したジョブをキューに戻すと、ジョブの「試行attempts
」の総数は増加します。それに応じて、ジョブクラスのtries
プロパティとmaxExceptions
プロパティを調整することをお勧めします。または、retryUntil
メソッドを使用して、ジョブが試行されなくなるまでの時間を定義することもできます。Releasing a rate limited job back onto the queue will still increment the job's total number of attempts
. You may wish to tune your tries
and maxExceptions
properties on your job class accordingly. Or, you may wish to use the retryUntil
method[#time-based-attempts] to define the amount of time until the job should no longer be attempted.
レート制限されているときにジョブを再試行させたくない場合は、dontRelease
メソッドを使用します。If you do not want a job to be retried when it is rate limited, you may use the dontRelease
method:
/**
* このジョブを通過させるミドルウェアを取得
*
* @return array<int, object>
*/
public function middleware(): array
{
return [(new RateLimited('backups'))->dontRelease()];
}
Note: Redisを使用している場合は、
Illuminate\Queue\Middleware\RateLimitedWithRedis
ミドルウェアを使用できます。これは、Redis用に微調整されており、基本的なレート制限ミドルウェアよりも効率的です。[!NOTE]
If you are using Redis, you may use theIlluminate\Queue\Middleware\RateLimitedWithRedis
middleware, which is fine-tuned for Redis and more efficient than the basic rate limiting middleware.
ジョブのオーバーラップの防止Preventing Job Overlaps
Laravelには、任意のキーに基づいてジョブの重複を防ぐことができるIlluminate\Queue\Middleware\WithoutOverlapping
ミドルウェアが含まれています。これは、キュー投入したジョブが、一度に1つのジョブによってのみ変更する必要があるリソースを変更している場合に役立ちます。Laravel includes an Illuminate\Queue\Middleware\WithoutOverlapping
middleware that allows you to prevent job overlaps based on an arbitrary key. This can be helpful when a queued job is modifying a resource that should only be modified by one job at a time.
たとえば、ユーザーのクレジットスコアを更新するキュー投入するジョブがあり、同じユーザーIDのクレジットスコア更新ジョブが重複しないようにしたいとします。これを実現するには、ジョブのmiddleware
メソッドでWithoutOverlapping
ミドルウェアを返してください。For example, let's imagine you have a queued job that updates a user's credit score and you want to prevent credit score update job overlaps for the same user ID. To accomplish this, you can return the WithoutOverlapping
middleware from your job's middleware
method:
use Illuminate\Queue\Middleware\WithoutOverlapping;
/**
* このジョブを通過させるミドルウェアを取得
*
* @return array<int, object>
*/
public function middleware(): array
{
return [new WithoutOverlapping($this->user->id)];
}
同じタイプの重複するジョブはすべてキューに戻されます。リリースしたジョブが再試行するまでに経過する必要のある秒数を指定することもできます。Any overlapping jobs of the same type will be released back to the queue. You may also specify the number of seconds that must elapse before the released job will be attempted again:
/**
* このジョブを通過させるミドルウェアを取得
*
* @return array<int, object>
*/
public function middleware(): array
{
return [(new WithoutOverlapping($this->order->id))->releaseAfter(60)];
}
重複するジョブをすぐに削除して再試行しないようにする場合は、dontRelease
メソッドを使用します。If you wish to immediately delete any overlapping jobs so that they will not be retried, you may use the dontRelease
method:
/**
* このジョブを通過させるミドルウェアを取得
*
* @return array<int, object>
*/
public function middleware(): array
{
return [(new WithoutOverlapping($this->order->id))->dontRelease()];
}
WithoutOverlapping
ミドルウェアはLaravelのアトミックロック機能により動作します。時々、ジョブは予期せずに失敗したり、ロックが解放されないような原因でタイムアウトしたりすることがあります。そのため、expireAfter
メソッドを使用して、ロックの有効期限を明示的に定義することができます。たとえば、以下の例では、ジョブが処理を開始してから3分後にWithoutOverlapping
ロックを解除するようにLaravelへ指示します。The WithoutOverlapping
middleware is powered by Laravel's atomic lock feature. Sometimes, your job may unexpectedly fail or timeout in such a way that the lock is not released. Therefore, you may explicitly define a lock expiration time using the expireAfter
method. For example, the example below will instruct Laravel to release the WithoutOverlapping
lock three minutes after the job has started processing:
/**
* このジョブを通過させるミドルウェアを取得
*
* @return array<int, object>
*/
public function middleware(): array
{
return [(new WithoutOverlapping($this->order->id))->expireAfter(180)];
}
Warning!
WithoutOverlapping
ミドルウェアには、ロックをサポートするキャッシュドライバが必要です。現在、memcached
、redis
、dynamodb
、database
、file
、array
キャッシュドライバはアトミックロックをサポートしています。[!WARNING]
TheWithoutOverlapping
middleware requires a cache driver that supports locks[/docs/{{version}}/cache#atomic-locks]. Currently, thememcached
,redis
,dynamodb
,database
,file
, andarray
cache drivers support atomic locks.
ジョブクラス間のロックキーの共用Sharing Lock Keys Across Job Classes
デフォルトのWithoutOverlapping
ミドルウェアは、同じクラスのジョブの重複を防ぐだけです。そのため、2つの異なるジョブクラスが同じロックキーを使用しても、重なり合うことは防げません。しかし、shared
メソッドを使用することで、ジョブクラス間でキーを共有するように、Laravelへ指示できます。By default, the WithoutOverlapping
middleware will only prevent overlapping jobs of the same class. So, although two different job classes may use the same lock key, they will not be prevented from overlapping. However, you can instruct Laravel to apply the key across job classes using the shared
method:
use Illuminate\Queue\Middleware\WithoutOverlapping;
class ProviderIsDown
{
// ...
public function middleware(): array
{
return [
(new WithoutOverlapping("status:{$this->provider}"))->shared(),
];
}
}
class ProviderIsUp
{
// ...
public function middleware(): array
{
return [
(new WithoutOverlapping("status:{$this->provider}"))->shared(),
];
}
}
例外による利用制限Throttling Exceptions
Laravelは、例外をスロットルすることができるIlluminate\Queue\Middleware\ThrottlesExceptions
ミドルウェアを用意しています。ジョブが指定した回数の例外を投げると、それ以降のジョブの実行は指定時間間隔が経過するまで延期されます。このミドルウェアは、不安定なサードパーティのサービスとやり取りするジョブで特に有効です。Laravel includes a Illuminate\Queue\Middleware\ThrottlesExceptions
middleware that allows you to throttle exceptions. Once the job throws a given number of exceptions, all further attempts to execute the job are delayed until a specified time interval lapses. This middleware is particularly useful for jobs that interact with third-party services that are unstable.
例えば、キュー投入したジョブがサードパーティのAPIとやりとりして、例外を投げるようになったとします。例外をスロットルするには、ジョブの middleware
メソッドからThrottlesExceptions
というミドルウェアを返します。通常、このミドルウェアは、時間ベースの試行を実装したジョブと組み合わせて使用します。For example, let's imagine a queued job that interacts with a third-party API that begins throwing exceptions. To throttle exceptions, you can return the ThrottlesExceptions
middleware from your job's middleware
method. Typically, this middleware should be paired with a job that implements time based attempts[#time-based-attempts]:
use DateTime;
use Illuminate\Queue\Middleware\ThrottlesExceptions;
/**
* このジョブを通過させるミドルウェアを取得
*
* @return array<int, object>
*/
public function middleware(): array
{
return [new ThrottlesExceptions(10, 5 * 60)];
}
/**
* ジョブがタイムアウトする時間を決定
*/
public function retryUntil(): DateTime
{
return now()->addMinutes(30);
}
このミドルウェアが受け付ける最初のコンストラクタ引数は、スロットルされる前にジョブが投げられる例外の数で、2番目のコンストラクタ引数は、ジョブがスロットルされた後に再度施行するまでの秒数です。上のコード例では、ジョブが連続して10回の例外を投げた場合、30分の時間制限の制約を受けながら、ジョブを再試行する前に5分待ちます。The first constructor argument accepted by the middleware is the number of exceptions the job can throw before being throttled, while the second constructor argument is the number of seconds that should elapse before the job is attempted again once it has been throttled. In the code example above, if the job throws 10 consecutive exceptions, we will wait 5 minutes before attempting the job again, constrained by the 30-minute time limit.
ジョブが例外を投げ、例外のしきい値にまだ達していない場合、ジョブは通常すぐに再試行されます。ただし、ミドルウェアをジョブに接続するときに、backoff
メソッドを呼び出すことで、ジョブを遅らせる必要がある数分を指定できます。When a job throws an exception but the exception threshold has not yet been reached, the job will typically be retried immediately. However, you may specify the number of minutes such a job should be delayed by calling the backoff
method when attaching the middleware to the job:
use Illuminate\Queue\Middleware\ThrottlesExceptions;
/**
* このジョブを通過させるミドルウェアを取得
*
* @return array<int, object>
*/
public function middleware(): array
{
return [(new ThrottlesExceptions(10, 5 * 60))->backoff(5)];
}
内部的には、このミドルウェアはLaravelのキャッシュシステムを使用してレート制限を実装し、ジョブのクラス名をキャッシュ「キー」として利用します。ジョブにミドルウェアを添付するときにby
メソッドを呼び出し、このキーを上書きできます。これは、同じサードパーティのサービスと対話するジョブが複数のジョブを持っている場合に役立ち、それらに共通のスロットル「バケット」を共有できます。Internally, this middleware uses Laravel's cache system to implement rate limiting, and the job's class name is utilized as the cache "key". You may override this key by calling the by
method when attaching the middleware to your job. This may be useful if you have multiple jobs interacting with the same third-party service and you would like them to share a common throttling "bucket":
use Illuminate\Queue\Middleware\ThrottlesExceptions;
/**
* このジョブを通過させるミドルウェアを取得
*
* @return array<int, object>
*/
public function middleware(): array
{
return [(new ThrottlesExceptions(10, 10 * 60))->by('key')];
}
このミドルウェアはデフォルトで、すべての例外をスロットル処理します。このミドルウェアをジョブへ指定するときに、when
メソッドを呼び出し、この動作を変更できます。この場合、when
メソッドで指定するクロージャが、true
を返した場合のみ、その例外をスロットルします。By default, this middleware will throttle every exception. You can modify this behaviour by invoking the when
method when attaching the middleware to your job. The exception will then only be throttled if closure provided to the when
method returns true
:
use Illuminate\Http\Client\HttpClientException;
use Illuminate\Queue\Middleware\ThrottlesExceptions;
/**
* ジョブを通過させるミドルウェアを取得
*
* @return array<int, object>
*/
public function middleware(): array
{
return [(new ThrottlesExceptions(10, 10 * 60))->when(
fn (Throwable $throwable) => $throwable instanceof HttpClientException
)];
}
スロットルした例外をアプリケーションの例外ハンドラへ報告させたい場合は、ミドルウェアをジョブへ指定するときに、report
メソッドを呼び出してください。report
めそっどのオプションとしてクロージャを指定でき、その指定クロージャがtrue
を返した場合にのみ例外を報告します。If you would like to have the throttled exceptions reported to your application's exception handler, you can do so by invoking the report
method when attaching the middleware to your job. Optionally, you may provide a closure to the report
method and the exception will only be reported if the given closure returns true
:
use Illuminate\Http\Client\HttpClientException;
use Illuminate\Queue\Middleware\ThrottlesExceptions;
/**
* ジョブを通過させるミドルウェアを取得
*
* @return array<int, object>
*/
public function middleware(): array
{
return [(new ThrottlesExceptions(10, 10 * 60))->report(
fn (Throwable $throwable) => $throwable instanceof HttpClientException
)];
}
Note: Redisを使用している場合は、Redis用に細かく調整され、基本的な例外スロットリングミドルウェアよりも効率的な、
Illuminate\Queue\Middleware\ThrottlesExceptionsWithRedis
ミドルウェアを使用できます。[!NOTE]
If you are using Redis, you may use theIlluminate\Queue\Middleware\ThrottlesExceptionsWithRedis
middleware, which is fine-tuned for Redis and more efficient than the basic exception throttling middleware.
ジョブのスキップSkipping Jobs
Skip
ミドルウェアを使うと、ジョブのロジックを変更せずに、ジョブをスキップ/削除するように指定できます。Skip::when
メソッドは指定条件をtrue
と評価した場合にジョブを削除し、Skip::unless
メソッドは指定条件をfalse
と評価した場合にジョブを削除します。The Skip
middleware allows you to specify that a job should be skipped / deleted without needing to modify the job's logic. The Skip::when
method will delete the job if the given condition evaluates to true
, while the Skip::unless
method will delete the job if the condition evaluates to false
:
use Illuminate\Queue\Middleware\Skip;
/**
* ジョブを通過させるミドルウェアの取得
*/
public function middleware(): array
{
return [
Skip::when($someCondition),
];
}
また、when
メソッドとunless
メソッドへ、Closure
を渡し、より複雑な条件判定を行うこともできます。You can also pass a Closure
to the when
and unless
methods for more complex conditional evaluation:
use Illuminate\Queue\Middleware\Skip;
/**
* ジョブを通過させるミドルウェアの取得
*/
public function middleware(): array
{
return [
Skip::when(function (): bool {
return $this->shouldSkip();
}),
];
}
ジョブのディスパッチDispatching Jobs
ジョブクラスを作成したら、ジョブ自体でdispatch
メソッドを使用してディスパッチできます。dispatch
メソッドに渡した引数は、ジョブのコンストラクタに渡されます。Once you have written your job class, you may dispatch it using the dispatch
method on the job itself. The arguments passed to the dispatch
method will be given to the job's constructor:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Jobs\ProcessPodcast;
use App\Models\Podcast;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class PodcastController extends Controller
{
/**
* 新しいポッドキャストの保存
*/
public function store(Request $request): RedirectResponse
{
$podcast = Podcast::create(/* ... */);
// ...
ProcessPodcast::dispatch($podcast);
return redirect('/podcasts');
}
}
条件付きでジョブをディスパッチする場合は、dispatchIf
メソッドとdispatchUnless
メソッドが使用できます。If you would like to conditionally dispatch a job, you may use the dispatchIf
and dispatchUnless
methods:
ProcessPodcast::dispatchIf($accountActive, $podcast);
ProcessPodcast::dispatchUnless($accountSuspended, $podcast);
新しいLaravelアプリケーションでは、sync
ドライバがデフォルトのキュードライバです。このドライバは現在のリクエストをフォアグラウンドで同期的にジョブを実行し、たいていのローカル開発時では便利です。もし、バックグラウンド処理のために実際にキューを開始したい場合は、アプリケーションのconfig/queue.php
設定ファイル内で、別のキュードライバを指定してください。In new Laravel applications, the sync
driver is the default queue driver. This driver executes jobs synchronously in the foreground of the current request, which is often convenient during local development. If you would like to actually begin queueing jobs for background processing, you may specify a different queue driver within your application's config/queue.php
configuration file.
ディスパッチの遅延Delayed Dispatching
ジョブをキューワーカによりすぐに処理できないように指定する場合は、ジョブをディスパッチするときにdelay
メソッドを使用します。たとえば、ジョブがディスパッチされてから10分後まで処理にされないように指定してみましょう。If you would like to specify that a job should not be immediately available for processing by a queue worker, you may use the delay
method when dispatching the job. For example, let's specify that a job should not be available for processing until 10 minutes after it has been dispatched:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Jobs\ProcessPodcast;
use App\Models\Podcast;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class PodcastController extends Controller
{
/**
* 新しいポッドキャストの保存
*/
public function store(Request $request): RedirectResponse
{
$podcast = Podcast::create(/* ... */);
// ...
ProcessPodcast::dispatch($podcast)
->delay(now()->addMinutes(10));
return redirect('/podcasts');
}
}
場合により、ジョブにはデフォルトの遅延が設定されていることがあります。この遅延を回避してジョブを即座にディスパッチしたい場合は、withoutDelay
メソッドを使用します。In some cases, jobs may have a default delay configured. If you need to bypass this delay and dispatch a job for immediate processing, you may use the withoutDelay
method:
ProcessPodcast::dispatch($podcast)->withoutDelay();
[!WARNING]
Warning! Amazon SQSキューサービスの最大遅延時間は15分です。
The Amazon SQS queue service has a maximum delay time of 15 minutes.
レスポンスがブラウザに送信された後のディスパッチDispatching After the Response is Sent to the Browser
別の方法として、dispatchAfterResponse
メソッドは、WebサーバでFastCGIを使っている場合、HTTPレスポンスがユーザーのブラウザへ送信されるまでジョブのディスパッチを遅らせます。これにより、キュー投入したジョブがまだ実行されている場合でも、ユーザーはアプリケーションの使用を開始できます。これは通常、電子メールの送信など、約1秒かかるジョブにのみ使用する必要があります。これは現在のHTTPリクエスト内で処理されるため、この方法でディスパッチされたジョブを処理するためにキューワーカを実行する必要はありません。Alternatively, the dispatchAfterResponse
method delays dispatching a job until after the HTTP response is sent to the user's browser if your web server is using FastCGI. This will still allow the user to begin using the application even though a queued job is still executing. This should typically only be used for jobs that take about a second, such as sending an email. Since they are processed within the current HTTP request, jobs dispatched in this fashion do not require a queue worker to be running in order for them to be processed:
use App\Jobs\SendNotification;
SendNotification::dispatchAfterResponse();
クロージャを「ディスパッチdispatch
」し、afterResponse
メソッドをdispatch
ヘルパにチェーンしても、HTTPレスポンスがブラウザに送信された後にクロージャを実行できます。You may also dispatch
a closure and chain the afterResponse
method onto the dispatch
helper to execute a closure after the HTTP response has been sent to the browser:
use App\Mail\WelcomeMessage;
use Illuminate\Support\Facades\Mail;
dispatch(function () {
Mail::to('taylor@example.com')->send(new WelcomeMessage);
})->afterResponse();
同期ディスパッチSynchronous Dispatching
ジョブをすぐに(同期して)ディスパッチする場合は、dispatchSync
メソッドを使用します。この方法を使用する場合、ジョブはキューに入らず、現在のプロセス内ですぐに実行されます。If you would like to dispatch a job immediately (synchronously), you may use the dispatchSync
method. When using this method, the job will not be queued and will be executed immediately within the current process:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Jobs\ProcessPodcast;
use App\Models\Podcast;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class PodcastController extends Controller
{
/**
* 新しいポッドキャストの保存
*/
public function store(Request $request): RedirectResponse
{
$podcast = Podcast::create(/* ... */);
// ポッドキャストの生成
ProcessPodcast::dispatchSync($podcast);
return redirect('/podcasts');
}
}
ジョブとデータベーストランザクションJobs & Database Transactions
データベーストランザクション内でジョブをディスパッチすることはまったく問題ありませんが、実際にジョブが正常に実行できるよう特別な注意を払う必要があります。トランザクション内でジョブをディスパッチする場合、親トランザクションがコミットされる前にジョブがワーカによって処理される可能性があります。これが発生した場合、データベーストランザクション中にモデルまたはデータベースレコードに加えた更新は、データベースにまだ反映されていない可能性があります。さらに、トランザクション内で作成されたモデルまたはデータベースレコードは、データベースに存在しない可能性があります。While it is perfectly fine to dispatch jobs within database transactions, you should take special care to ensure that your job will actually be able to execute successfully. When dispatching a job within a transaction, it is possible that the job will be processed by a worker before the parent transaction has committed. When this happens, any updates you have made to models or database records during the database transaction(s) may not yet be reflected in the database. In addition, any models or database records created within the transaction(s) may not exist in the database.
幸いに、Laravelはこの問題を回避する方法をいくつか提供しています。まず、キュー接続の設定配列でafter_commit
接続オプションを設定できます。Thankfully, Laravel provides several methods of working around this problem. First, you may set the after_commit
connection option in your queue connection's configuration array:
'redis' => [
'driver' => 'redis',
// ...
'after_commit' => true,
],
after_commit
オプションがtrue
の場合、データベーストランザクション内でジョブをディスパッチすることができます。ただし、Laravel は実際にジョブをディスパッチする前に、開いている親データベーストランザクションがコミットされるまで待機します。もちろん、現在開いているデータベーストランザクションがない場合は、ジョブはすぐにディスパッチされます。When the after_commit
option is true
, you may dispatch jobs within database transactions; however, Laravel will wait until the open parent database transactions have been committed before actually dispatching the job. Of course, if no database transactions are currently open, the job will be dispatched immediately.
トランザクション中に発生した例外によりロールバックされた場合、そのトランザクション中にディスパッチされたジョブは破棄されます。If a transaction is rolled back due to an exception that occurs during the transaction, the jobs that were dispatched during that transaction will be discarded.
Note:
after_commit
設定オプションをtrue
に設定すると、開いているすべてのデータベーストランザクションがコミットされた後、キュー投入したイベントリスナ、メーラブル、通知、およびブロードキャストイベントもディスパッチされます。[!NOTE]
Setting theafter_commit
configuration option totrue
will also cause any queued event listeners, mailables, notifications, and broadcast events to be dispatched after all open database transactions have been committed.
コミットディスパッチ動作をインラインで指定Specifying Commit Dispatch Behavior Inline
after_commit
キュー接続設定オプションをtrue
に設定しない場合でも、開いているすべてのデータベーストランザクションがコミットされた後に特定のジョブをディスパッチする必要があることを示すことができます。これを実現するには、afterCommit
メソッドをディスパッチ操作にチェーンします。If you do not set the after_commit
queue connection configuration option to true
, you may still indicate that a specific job should be dispatched after all open database transactions have been committed. To accomplish this, you may chain the afterCommit
method onto your dispatch operation:
use App\Jobs\ProcessPodcast;
ProcessPodcast::dispatch($podcast)->afterCommit();
同様に、after_commit
設定オプションがtrue
に設定されている場合でも、開いているデータベーストランザクションがコミットするのを待たずに、特定のジョブをすぐにディスパッチする必要があることを示すことができます。Likewise, if the after_commit
configuration option is set to true
, you may indicate that a specific job should be dispatched immediately without waiting for any open database transactions to commit:
ProcessPodcast::dispatch($podcast)->beforeCommit();
ジョブチェーンJob Chaining
ジョブチェーンを使用すると、プライマリジョブが正常に実行された後から順番に実行する必要があるキュー投入するジョブのリストを指定できます。シーケンス内の1つのジョブが失敗した場合は、残りのジョブを実行しません。キュー投入するジョブチェーンを実行するには、Bus
ファサードが提供するchain
メソッドを使用します。Laravelのコマンドバスは、キュー投入するジョブのディスパッチをその上で構築している、下位レベルのコンポーネントです。Job chaining allows you to specify a list of queued jobs that should be run in sequence after the primary job has executed successfully. If one job in the sequence fails, the rest of the jobs will not be run. To execute a queued job chain, you may use the chain
method provided by the Bus
facade. Laravel's command bus is a lower level component that queued job dispatching is built on top of:
use App\Jobs\OptimizePodcast;
use App\Jobs\ProcessPodcast;
use App\Jobs\ReleasePodcast;
use Illuminate\Support\Facades\Bus;
Bus::chain([
new ProcessPodcast,
new OptimizePodcast,
new ReleasePodcast,
])->dispatch();
ジョブクラスインスタンスをチェーンすることに加えて、クロージャをチェーンすることもできます。In addition to chaining job class instances, you may also chain closures:
Bus::chain([
new ProcessPodcast,
new OptimizePodcast,
function () {
Podcast::update(/* ... */);
},
])->dispatch();
Warning! ジョブ内で
$this->delete()
メソッドを使用してジョブを削除しても、チェーンしたジョブの処理が妨げられることはありません。チェーンは、チェーン内のジョブが失敗した場合にのみ実行を停止します。[!WARNING]
Deleting jobs using the$this->delete()
method within the job will not prevent chained jobs from being processed. The chain will only stop executing if a job in the chain fails.
チェーン接続とキューChain Connection and Queue
チェーンジョブに使用する接続とキューを指定する場合は、onConnection
メソッドとonQueue
メソッドを使用します。キュー投入する各ジョブに別の接続/キューが明示的に指定されない限り、これらのメソッドでチェーンに対し指定するキュー接続とキュー名を使用します。If you would like to specify the connection and queue that should be used for the chained jobs, you may use the onConnection
and onQueue
methods. These methods specify the queue connection and queue name that should be used unless the queued job is explicitly assigned a different connection / queue:
Bus::chain([
new ProcessPodcast,
new OptimizePodcast,
new ReleasePodcast,
])->onConnection('redis')->onQueue('podcasts')->dispatch();
チェーンへのジョブ追加Adding Jobs to the Chain
時に、既存のジョブチェーンへ、そのチェーン内の別のジョブからジョブを追加する必要があるかもしれません。それにはprependToChain
メソッドとappendToChain
メソッドを使用してください。Occasionally, you may need to prepend or append a job to an existing job chain from within another job in that chain. You may accomplish this using the prependToChain
and appendToChain
methods:
/**
* ジョブを実行
*/
public function handle(): void
{
// ...
// Prepend to the current chain, run job immediately after current job...
$this->prependToChain(new TranscribePodcast);
// Append to the current chain, run job at end of chain...
$this->appendToChain(new TranscribePodcast);
}
チェーンの失敗Chain Failures
ジョブをチェーンする場合、catch
メソッドを使用して、チェーン内のジョブが失敗した場合に呼び出すクロージャを指定できます。指定するコールバックは、ジョブの失敗の原因となったThrowable
インスタンスを受け取ります。When chaining jobs, you may use the catch
method to specify a closure that should be invoked if a job within the chain fails. The given callback will receive the Throwable
instance that caused the job failure:
use Illuminate\Support\Facades\Bus;
use Throwable;
Bus::chain([
new ProcessPodcast,
new OptimizePodcast,
new ReleasePodcast,
])->catch(function (Throwable $e) {
// チェーン内のジョブが失敗
})->dispatch();
Warning! チェーンコールバックはシリアライズされ、Laravelのキューによって後ほど実行されるため、チェーンコールバック内で
$this
変数を使用するべきではありません。[!WARNING]
Since chain callbacks are serialized and executed at a later time by the Laravel queue, you should not use the$this
variable within chain callbacks.
キューと接続のカスタマイズCustomizing the Queue and Connection
特定のキューへのディスパッチDispatching to a Particular Queue
ジョブを他のキューに投入することで、キュー投入したジョブを「分類」し、さまざまなキューに割り当てるワーカの数に優先度を付けることもできます。これは、キュー設定ファイルで定義している他のキュー「接続」にジョブを投入するのではなく、同じ接続内の特定のキューにのみプッシュすることに注意してください。キューを指定するには、ジョブをディスパッチするときにonQueue
メソッドを使用します。By pushing jobs to different queues, you may "categorize" your queued jobs and even prioritize how many workers you assign to various queues. Keep in mind, this does not push jobs to different queue "connections" as defined by your queue configuration file, but only to specific queues within a single connection. To specify the queue, use the onQueue
method when dispatching the job:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Jobs\ProcessPodcast;
use App\Models\Podcast;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class PodcastController extends Controller
{
/**
* 新しいポッドキャストの保存
*/
public function store(Request $request): RedirectResponse
{
$podcast = Podcast::create(/* ... */);
// ポッドキャストの生成
ProcessPodcast::dispatch($podcast)->onQueue('processing');
return redirect('/podcasts');
}
}
または、ジョブのコンストラクタ内でonQueue
メソッドを呼び出して、ジョブのキューを指定することもできます。Alternatively, you may specify the job's queue by calling the onQueue
method within the job's constructor:
<?php
namespace App\Jobs;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
class ProcessPodcast implements ShouldQueue
{
use Queueable;
/**
* 新しいジョブインスタンスの生成
*/
public function __construct()
{
$this->onQueue('processing');
}
}
特定の接続へのディスパッチDispatching to a Particular Connection
アプリケーションが複数のキュー接続と対話する場合は、onConnection
メソッドを使用してジョブをプッシュする接続を指定できます。If your application interacts with multiple queue connections, you may specify which connection to push a job to using the onConnection
method:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Jobs\ProcessPodcast;
use App\Models\Podcast;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class PodcastController extends Controller
{
/**
* 新しいポッドキャストの保存
*/
public function store(Request $request): RedirectResponse
{
$podcast = Podcast::create(/* ... */);
// ポッドキャストの生成
ProcessPodcast::dispatch($podcast)->onConnection('sqs');
return redirect('/podcasts');
}
}
onConnection
メソッドとonQueue
メソッドをチェーンして、ジョブの接続とキューを指定できます。You may chain the onConnection
and onQueue
methods together to specify the connection and the queue for a job:
ProcessPodcast::dispatch($podcast)
->onConnection('sqs')
->onQueue('processing');
または、ジョブのコンストラクター内でonConnection
メソッドを呼び出すことにより、ジョブの接続を指定することもできます。Alternatively, you may specify the job's connection by calling the onConnection
method within the job's constructor:
<?php
namespace App\Jobs;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
class ProcessPodcast implements ShouldQueue
{
use Queueable;
/**
* 新しいジョブインスタンスの生成
*/
public function __construct()
{
$this->onConnection('sqs');
}
}
最大試行回数/タイムアウト値の指定Specifying Max Job Attempts / Timeout Values
最大試行回数Max Attempts
キュー投入したジョブの1つでエラーが発生した場合、そのジョブが無期限に再試行し続けることを普通は望まないでしょう。したがって、Laravelは、ジョブを試行できる回数または期間を指定するさまざまな方法を提供しています。If one of your queued jobs is encountering an error, you likely do not want it to keep retrying indefinitely. Therefore, Laravel provides various ways to specify how many times or for how long a job may be attempted.
ジョブを試行できる最大回数を指定する1つの方法は、Artisanコマンドラインの--tries
スイッチを使用することです。これは、処理中のジョブへ試行回数を指定しない限り、ワーカが処理するすべてのジョブに適用します。One approach to specifying the maximum number of times a job may be attempted is via the --tries
switch on the Artisan command line. This will apply to all jobs processed by the worker unless the job being processed specifies the number of times it may be attempted:
php artisan queue:work --tries=3
ジョブが最大試行回数を超えると、「失敗した」ジョブと見なされます。失敗したジョブの処理の詳細は、失敗したジョブのドキュメントを参照してください。queue:work
コマンドで、--tries=0
を指定した場合は、ジョブを無制限に再試行します。If a job exceeds its maximum number of attempts, it will be considered a "failed" job. For more information on handling failed jobs, consult the failed job documentation[#dealing-with-failed-jobs]. If --tries=0
is provided to the queue:work
command, the job will be retried indefinitely.
ジョブクラス自体でジョブを試行できる最大回数を定義することで、より詳細なアプローチをとることもできます。ジョブで最大試行回数が指定されている場合、コマンドラインで指定する--tries
値よりも優先されます。You may take a more granular approach by defining the maximum number of times a job may be attempted on the job class itself. If the maximum number of attempts is specified on the job, it will take precedence over the --tries
value provided on the command line:
<?php
namespace App\Jobs;
class ProcessPodcast implements ShouldQueue
{
/**
* ジョブを試行する回数を決定
*
* @var int
*/
public $tries = 5;
}
特定ジョブの最大試行回数を動的に制御する必要がある場合は、そのジョブにtries
メソッドを定義します。If you need dynamic control over a particular job's maximum attempts, you may define a tries
method on the job:
/**
* ジョブを試行する回数を決定
*/
public function tries(): int
{
return 5;
}
時間ベースの試行Time Based Attempts
ジョブが失敗するまでに試行できる回数を定義する代わりに、ジョブをそれ以上実行しない時間を定義することもできます。これにより、特定の時間枠内でジョブを何度も試行できます。ジョブを試行しないタイムアウトを定義するには、ジョブクラスにretryUntil
メソッドを追加します。このメソッドはDateTime
インスタンスを返す必要があります:As an alternative to defining how many times a job may be attempted before it fails, you may define a time at which the job should no longer be attempted. This allows a job to be attempted any number of times within a given time frame. To define the time at which a job should no longer be attempted, add a retryUntil
method to your job class. This method should return a DateTime
instance:
use DateTime;
/**
* ジョブがタイムアウトする時間を決定
*/
public function retryUntil(): DateTime
{
return now()->addMinutes(10);
}
キュー投入済みイベントリスナで
Note:tries
プロパティまたはretryUntil
メソッドを定義することもできます。[!NOTE]
You may also define atries
property orretryUntil
method on your queued event listeners[/docs/{{version}}/events#queued-event-listeners].
最大例外数Max Exceptions
あるジョブを何度も試行してもよいが、所定の数の未処理の例外が発生した場合には失敗するように指定したい場合があるかもしれません。(release
メソッドによって直接解放されるのではなく、所定の数の未処理の例外が発生した場合。)これを実現するには、ジョブクラスに maxExceptions
プロパティを定義します。Sometimes you may wish to specify that a job may be attempted many times, but should fail if the retries are triggered by a given number of unhandled exceptions (as opposed to being released by the release
method directly). To accomplish this, you may define a maxExceptions
property on your job class:
<?php
namespace App\Jobs;
use Illuminate\Support\Facades\Redis;
class ProcessPodcast implements ShouldQueue
{
/**
* ジョブを試行する回数を決定
*
* @var int
*/
public $tries = 25;
/**
* 失敗する前に許可する未処理の例外の最大数
*
* @var int
*/
public $maxExceptions = 3;
/**
* ジョブの実行
*/
public function handle(): void
{
Redis::throttle('key')->allow(10)->every(60)->then(function () {
// ロックを取得し、ポッドキャストを処理する
}, function () {
// ロックを獲得できなかった
return $this->release(10);
});
}
}
この例では、アプリケーションがRedisロックを取得できない場合、ジョブは10秒間解放され、最大25回再試行され続けます。ただし、ジョブによって3つの未処理の例外がスローされると、ジョブは失敗します。In this example, the job is released for ten seconds if the application is unable to obtain a Redis lock and will continue to be retried up to 25 times. However, the job will fail if three unhandled exceptions are thrown by the job.
タイムアウトTimeout
多くの場合、キュー投入したジョブにかかると予想されるおおよその時間をあなたは知っています。このため、Laravelでは「タイムアウト」値も指定できます。デフォルトのタイムアウト値は60秒です。ジョブがタイムアウト値で指定する秒数より長く処理されている場合、ジョブを処理しているワーカはエラーで終了します。通常、ワーカはサーバで設定したプロセスマネージャによって自動的に再起動されます。Often, you know roughly how long you expect your queued jobs to take. For this reason, Laravel allows you to specify a "timeout" value. By default, the timeout value is 60 seconds. If a job is processing for longer than the number of seconds specified by the timeout value, the worker processing the job will exit with an error. Typically, the worker will be restarted automatically by a process manager configured on your server[#supervisor-configuration].
ジョブを実行できる最大秒数は、Artisanコマンドラインの--timeout
スイッチを使用して指定できます。The maximum number of seconds that jobs can run may be specified using the --timeout
switch on the Artisan command line:
php artisan queue:work --timeout=30
ジョブが継続的にタイムアウトして最大試行回数を超えた場合、失敗としてマークされます。If the job exceeds its maximum attempts by continually timing out, it will be marked as failed.
また、ジョブクラス自体でジョブの実行を許可する最大秒数を定義することもできます。ジョブでタイムアウトが指定されている場合、コマンドラインで指定されているタイムアウトよりも優先されます。You may also define the maximum number of seconds a job should be allowed to run on the job class itself. If the timeout is specified on the job, it will take precedence over any timeout specified on the command line:
<?php
namespace App\Jobs;
class ProcessPodcast implements ShouldQueue
{
/**
* タイムアウトになる前にジョブを実行できる秒数
*
* @var int
*/
public $timeout = 120;
}
ソケットや送信HTTP接続などのI/Oブロッキングプロセスが、指定するタイムアウトを尊重しない場合があります。したがって、これらの機能を使用するときは、常にAPIを使用してタイムアウトを指定するようにしてください。たとえば、Guzzleを使用する場合は、常に接続を指定し、タイムアウト値をリクエストする必要があります。Sometimes, IO blocking processes such as sockets or outgoing HTTP connections may not respect your specified timeout. Therefore, when using these features, you should always attempt to specify a timeout using their APIs as well. For example, when using Guzzle, you should always specify a connection and request timeout value.
Warning! ジョブのタイムアウトを指定するには、
pcntl
PHP拡張モジュールをインストールする必要があります。加えて、ジョブの"timeout"の値は、常に"retry after"値よりも小さい必要があります。そうしない場合、ジョブの実行が終了する前に再試行したり、タイムアウトしたりする可能性があります。[!WARNING]
Thepcntl
PHP extension must be installed in order to specify job timeouts. In addition, a job's "timeout" value should always be less than its "retry after"[#job-expiration] value. Otherwise, the job may be re-attempted before it has actually finished executing or timed out.
タイムアウトによる失敗Failing on Timeout
タイムアウトによるジョブの失敗をマークしたい場合は、ジョブクラスに$failOnTimeout
プロパティを定義します。If you would like to indicate that a job should be marked as failed[#dealing-with-failed-jobs] on timeout, you may define the $failOnTimeout
property on the job class:
/**
* ジョブがタイムアウトで失敗したとマークするかを指定
*
* @var bool
*/
public $failOnTimeout = true;
エラー処理Error Handling
ジョブの処理中に例外が投げられた場合、ジョブは自動的にキューへ解放されるため、再試行できます。ジョブは、アプリケーションで許可されている最大回数試行されるまで解放され続けます。最大試行回数は、queue:work
Artisanコマンドで使用される--tries
スイッチによって定義されます。または、最大試行回数をジョブクラス自体で定義することもできます。キューワーカの実行の詳細は、以下で見つかります。If an exception is thrown while the job is being processed, the job will automatically be released back onto the queue so it may be attempted again. The job will continue to be released until it has been attempted the maximum number of times allowed by your application. The maximum number of attempts is defined by the --tries
switch used on the queue:work
Artisan command. Alternatively, the maximum number of attempts may be defined on the job class itself. More information on running the queue worker can be found below[#running-the-queue-worker].
手作業でジョブを解放Manually Releasing a Job
後で再試行できるように、ジョブを手作業でキューへ戻したい場合があります。これは、release
メソッドを呼び出すことで実現できます。Sometimes you may wish to manually release a job back onto the queue so that it can be attempted again at a later time. You may accomplish this by calling the release
method:
/**
* ジョブの実行
*/
public function handle(): void
{
// ...
$this->release();
}
デフォルトでrelease
メソッドは、ジョブをキューに戻してすぐに処理できるようにします。しかし、release
メソッドへ整数値または日付のインスタンスを渡すことにより、指定秒数が経過するまでジョブを処理しないように、キューへ指示できます:By default, the release
method will release the job back onto the queue for immediate processing. However, you may instruct the queue to not make the job available for processing until a given number of seconds has elapsed by passing an integer or date instance to the release
method:
$this->release(10);
$this->release(now()->addSeconds(10));
手作業でジョブを失敗させるManually Failing a Job
場合によっては、ジョブを「失敗した」として手作業でマークする必要があります。これには、fail
メソッドを呼び出してください。Occasionally you may need to manually mark a job as "failed". To do so, you may call the fail
method:
/**
* ジョブの実行
*/
public function handle(): void
{
// ...
$this->fail();
}
キャッチした例外が原因でジョブを失敗としてマークしたい場合は、その例外をfail
メソッドへ渡せます。また、エラーメッセージを文字列で渡せば、例外に変換してくれるのも便利でしょう。If you would like to mark your job as failed because of an exception that you have caught, you may pass the exception to the fail
method. Or, for convenience, you may pass a string error message which will be converted to an exception for you:
$this->fail($exception);
$this->fail('Something went wrong.');
ジョブの失敗の処理に関するドキュメントを確認してください。[!NOTE]
Note: 失敗したジョブの詳細は、
For more information on failed jobs, check out the documentation on dealing with job failures[#dealing-with-failed-jobs].
ジョブバッチJob Batching
Laravelのジョブバッチ機能は、ジョブのバッチ処理を簡単に実行し、ジョブのバッチが実行完了したときに何らかのアクションを実行できます。使い始める前に、ジョブバッチの完了率などのメタ情報を含むテーブルを構築するために、データベースマイグレーションを作成する必要があります。このマイグレーションはmake:queue-batches-table
Artisanコマンドを使用して生成できます。Laravel's job batching feature allows you to easily execute a batch of jobs and then perform some action when the batch of jobs has completed executing. Before getting started, you should create a database migration to build a table which will contain meta information about your job batches, such as their completion percentage. This migration may be generated using the make:queue-batches-table
Artisan command:
php artisan make:queue-batches-table
php artisan migrate
Batchableジョブの定義Defining Batchable Jobs
バッチ可能なジョブを定義するには、通常どおりキュー可能なジョブを作成する必要があります。ただし、ジョブクラスにIlluminate\Bus\Batchable
トレイトを追加する必要があります。このトレイトは、ジョブを実行している現在のバッチを取得するために使用するbatch
メソッドへのアクセスを提供します。To define a batchable job, you should create a queueable job[#creating-jobs] as normal; however, you should add the Illuminate\Bus\Batchable
trait to the job class. This trait provides access to a batch
method which may be used to retrieve the current batch that the job is executing within:
<?php
namespace App\Jobs;
use Illuminate\Bus\Batchable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
class ImportCsv implements ShouldQueue
{
use Batchable, Queueable;
/**
* ジョブの実行
*/
public function handle(): void
{
if ($this->batch()->cancelled()) {
// バッチがキャンセルされたかどうかを判定
return;
}
// CSVファイルの一部をインポート…
}
}
バッチのディスパッチDispatching Batches
ジョブのバッチをディスパッチするには、Bus
ファサードのbatch
メソッドを使用する必要があります。もちろん、バッチ処理は、完了コールバックと組み合わせるとき、主に役立ちます。したがってthen
、catch
、finally
メソッドを使用して、バッチの完了コールバックを定義できます。これらの各コールバックは、呼び出されたときにIlluminate\Bus\Batch
インスタンスを受け取ります。以下の例では、CSVファイルから指定する数の行をそれぞれ処理するジョブのバッチをキューに入れていると仮定します。To dispatch a batch of jobs, you should use the batch
method of the Bus
facade. Of course, batching is primarily useful when combined with completion callbacks. So, you may use the then
, catch
, and finally
methods to define completion callbacks for the batch. Each of these callbacks will receive an Illuminate\Bus\Batch
instance when they are invoked. In this example, we will imagine we are queueing a batch of jobs that each process a given number of rows from a CSV file:
use App\Jobs\ImportCsv;
use Illuminate\Bus\Batch;
use Illuminate\Support\Facades\Bus;
use Throwable;
$batch = Bus::batch([
new ImportCsv(1, 100),
new ImportCsv(101, 200),
new ImportCsv(201, 300),
new ImportCsv(301, 400),
new ImportCsv(401, 500),
])->before(function (Batch $batch) {
// バッチは生成されたが、ジョブは追加されていない
})->progress(function (Batch $batch) {
// 一つのジョブが正常に終了
})->then(function (Batch $batch) {
// すべてのジョブが正常に完了
})->catch(function (Batch $batch, Throwable $e) {
// バッチジョブの失敗をはじめて検出
})->finally(function (Batch $batch) {
// バッチの実行が終了
})->dispatch();
return $batch->id;
バッチのIDは、$batch->id
プロパティを介してアクセスでき、ディスパッチ後のバッチに関する情報をLaravelコマンドバスに照会するために使用できます。The batch's ID, which may be accessed via the $batch->id
property, may be used to query the Laravel command bus[#inspecting-batches] for information about the batch after it has been dispatched.
Warning! バッチコールバックはシリアライズされ、Laravelのキューが後ほど実行するため、コールバック内で
$this
変数を使用すべきではありません。さらに、バッチジョブはデータベーストランザクション内へラップするため、暗黙のコミットを行うデータベースステートメントをジョブ内で実行しないでください。[!WARNING]
Since batch callbacks are serialized and executed at a later time by the Laravel queue, you should not use the$this
variable within the callbacks. In addition, since batched jobs are wrapped within database transactions, database statements that trigger implicit commits should not be executed within the jobs.
名前付きバッチNaming Batches
LaravelHorizonやLaravelTelescopeなどの一部のツールは、バッチに名前が付けられている場合、バッチのよりユーザーフレンドリーなデバッグ情報を提供します。バッチに任意の名前を割り当てるには、バッチを定義するときにname
メソッドを呼び出すことができます。Some tools such as Laravel Horizon and Laravel Telescope may provide more user-friendly debug information for batches if batches are named. To assign an arbitrary name to a batch, you may call the name
method while defining the batch:
$batch = Bus::batch([
// ...
])->then(function (Batch $batch) {
// すべてのジョブが正常に完了
})->name('Import CSV')->dispatch();
バッチ接続とキューBatch Connection and Queue
バッチ処理されたジョブに使用する接続とキューを指定する場合は、onConnection
メソッドとonQueue
メソッドを使用できます。バッチ処理するすべてのジョブは、同じ接続とキュー内で実行する必要があります。If you would like to specify the connection and queue that should be used for the batched jobs, you may use the onConnection
and onQueue
methods. All batched jobs must execute within the same connection and queue:
$batch = Bus::batch([
// ...
])->then(function (Batch $batch) {
// すべてのジョブが正常に完了
})->onConnection('redis')->onQueue('imports')->dispatch();
チェーンとバッチChains and Batches
配列内に配置することにより、バッチ内で一連のジョブチェーンを定義できます。たとえば、2つのジョブチェーンを並行して実行し、両方のジョブチェーンの処理が終了したときにコールバックを実行するとしましょう。You may define a set of chained jobs[#job-chaining] within a batch by placing the chained jobs within an array. For example, we may execute two job chains in parallel and execute a callback when both job chains have finished processing:
use App\Jobs\ReleasePodcast;
use App\Jobs\SendPodcastReleaseNotification;
use Illuminate\Bus\Batch;
use Illuminate\Support\Facades\Bus;
Bus::batch([
[
new ReleasePodcast(1),
new SendPodcastReleaseNotification(1),
],
[
new ReleasePodcast(2),
new SendPodcastReleaseNotification(2),
],
])->then(function (Batch $batch) {
// ...
})->dispatch();
逆に、チェーン内でバッチを定義すれば、チェーン内でジョブのバッチを実行できます。例えば、最初に複数のポッドキャストをリリースするジョブのバッチを実行し、次にリリース通知を送信するジョブのバッチを実行することができます:Conversely, you may run batches of jobs within a chain[#job-chaining] by defining batches within the chain. For example, you could first run a batch of jobs to release multiple podcasts then a batch of jobs to send the release notifications:
use App\Jobs\FlushPodcastCache;
use App\Jobs\ReleasePodcast;
use App\Jobs\SendPodcastReleaseNotification;
use Illuminate\Support\Facades\Bus;
Bus::chain([
new FlushPodcastCache,
Bus::batch([
new ReleasePodcast(1),
new ReleasePodcast(2),
]),
Bus::batch([
new SendPodcastReleaseNotification(1),
new SendPodcastReleaseNotification(2),
]),
])->dispatch();
バッチへのジョブ追加Adding Jobs to Batches
バッチ処理するジョブ内からそのバッチへジョブを追加できると便利です。このパターンは、Webリクエスト中にディスパッチするのに時間がかかりすぎるだろう何千ものジョブをバッチ処理する必要がある場合に役立ちます。したがって、代わりに、バッチをより多くのジョブとハイドレイトする「ローダー」ジョブを最初のバッチとしてディスパッチすることを推奨します。Sometimes it may be useful to add additional jobs to a batch from within a batched job. This pattern can be useful when you need to batch thousands of jobs which may take too long to dispatch during a web request. So, instead, you may wish to dispatch an initial batch of "loader" jobs that hydrate the batch with even more jobs:
$batch = Bus::batch([
new LoadImportBatch,
new LoadImportBatch,
new LoadImportBatch,
])->then(function (Batch $batch) {
// すべてのジョブが正常に完了
})->name('Import Contacts')->dispatch();
この例では、LoadImportBatch
ジョブを使用して、追加のジョブでバッチをハイドレイトします。これを実現するために、ジョブのbatch
メソッドを介してアクセスできるバッチインスタンスでadd
メソッドを使用できます。In this example, we will use the LoadImportBatch
job to hydrate the batch with additional jobs. To accomplish this, we may use the add
method on the batch instance that may be accessed via the job's batch
method:
use App\Jobs\ImportContacts;
use Illuminate\Support\Collection;
/**
* ジョブの実行
*/
public function handle(): void
{
if ($this->batch()->cancelled()) {
return;
}
$this->batch()->add(Collection::times(1000, function () {
return new ImportContacts;
}));
}
[!WARNING]
Warning! 同じバッチに属するジョブ内からのみ、バッチにジョブを追加できます。
You may only add jobs to a batch from within a job that belongs to the same batch.
バッチの検査Inspecting Batches
バッチ完了コールバックに渡されるIlluminate\Bus\Batch
インスタンスは、特定のジョブのバッチを操作および検査をサポートするために、さまざまなプロパティとメソッドを用意しています。The Illuminate\Bus\Batch
instance that is provided to batch completion callbacks has a variety of properties and methods to assist you in interacting with and inspecting a given batch of jobs:
// バッチのUUID
$batch->id;
// バッチの名前(該当する場合)
$batch->name;
// バッチに割り当てたジョブの数
$batch->totalJobs;
// キューにより処理されていないジョブの数
$batch->pendingJobs;
// 失敗したジョブの数
$batch->failedJobs;
// これまでに処理したジョブの数
$batch->processedJobs();
// バッチの完了率(0-100)
$batch->progress();
// バッチの実行が終了したかを判定
$batch->finished();
// バッチの実行をキャンセル
$batch->cancel();
// バッチがキャンセルされたかを判定
$batch->cancelled();
ルートからバッチを返すReturning Batches From Routes
すべてのIlluminate\Bus\Batch
インスタンスはJSONシリアル化可能です。つまり、アプリケーションのルートの1つから直接それらを返し、完了の進行状況など、バッチに関する情報を含むJSONペイロードを取得できます。これにより、バッチの完了の進行状況に関する情報をアプリケーションのUIに表示するのに便利です。All Illuminate\Bus\Batch
instances are JSON serializable, meaning you can return them directly from one of your application's routes to retrieve a JSON payload containing information about the batch, including its completion progress. This makes it convenient to display information about the batch's completion progress in your application's UI.
IDでバッチを取得するには、Bus
ファサードのfindBatch
メソッドを使用します。To retrieve a batch by its ID, you may use the Bus
facade's findBatch
method:
use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Facades\Route;
Route::get('/batch/{batchId}', function (string $batchId) {
return Bus::findBatch($batchId);
});
バッチのキャンセルCancelling Batches
特定のバッチの実行をキャンセルする必要が起きることもあるでしょう。これは、Illuminate\Bus\Batch
インスタンスでcancel
メソッドを呼び出すことで実行できます。Sometimes you may need to cancel a given batch's execution. This can be accomplished by calling the cancel
method on the Illuminate\Bus\Batch
instance:
/**
* ジョブの実行
*/
public function handle(): void
{
if ($this->user->exceedsImportLimit()) {
return $this->batch()->cancel();
}
if ($this->batch()->cancelled()) {
return;
}
}
前例で気づかれたかもしれませんが、バッチジョブは通常、実行を続ける前に対応するバッチがキャンセルされていることを判定する必要があります。しかし、便利なように、代わりに SkipIfBatchCancelled
ミドルウェアをジョブへ割り当てできます。名前が示すように、このミドルウェアは、対応するバッチがキャンセルされた場合、ジョブを処理しないようにLaravelに指示します。As you may have noticed in the previous examples, batched jobs should typically determine if their corresponding batch has been cancelled before continuing execution. However, for convenience, you may assign the SkipIfBatchCancelled
middleware[#job-middleware] to the job instead. As its name indicates, this middleware will instruct Laravel to not process the job if its corresponding batch has been cancelled:
use Illuminate\Queue\Middleware\SkipIfBatchCancelled;
/**
* このジョブを通過させるミドルウェアを取得
*/
public function middleware(): array
{
return [new SkipIfBatchCancelled];
}
バッチの失敗Batch Failures
バッチ処理されたジョブが失敗すると、catch
コールバック(割り当てられている場合)が呼び出されます。このコールバックは、バッチ内で失敗した最初のジョブに対してのみ呼び出されます。When a batched job fails, the catch
callback (if assigned) will be invoked. This callback is only invoked for the first job that fails within the batch.
失敗の許可Allowing Failures
バッチ内のジョブが失敗すると、Laravelは自動的にバッチを「キャンセル済み」としてマークします。必要に応じて、この動作を無効にして、ジョブの失敗によってバッチがキャンセル済みとして自動的にマークされないようにすることができます。これは、バッチのディスパッチ中にallowFailures
メソッドを呼び出すことで実現できます。When a job within a batch fails, Laravel will automatically mark the batch as "cancelled". If you wish, you may disable this behavior so that a job failure does not automatically mark the batch as cancelled. This may be accomplished by calling the allowFailures
method while dispatching the batch:
$batch = Bus::batch([
// ...
])->then(function (Batch $batch) {
// すべてのジョブが正常に完了
})->allowFailures()->dispatch();
失敗したバッチジョブの再試行Retrying Failed Batch Jobs
便利なように、Laravelはqueue:retry-batch
Artisanコマンドを用意しており、特定のバッチで失敗したすべてのジョブを簡単に再試行できます。queue:retry-batch
コマンドは、失敗したジョブを再試行する必要があるバッチのUUIDを引数に取ります。For convenience, Laravel provides a queue:retry-batch
Artisan command that allows you to easily retry all of the failed jobs for a given batch. The queue:retry-batch
command accepts the UUID of the batch whose failed jobs should be retried:
php artisan queue:retry-batch 32dbc76c-4f82-4749-b610-a639fe0099b5
バッチの整理Pruning Batches
整理しないと、job_batches
テーブルにレコードがあっという間に蓄積されます。これを軽減するには、queue:prune-batches
Artisanコマンドを毎日実行するようにスケジュールする必要があります。Without pruning, the job_batches
table can accumulate records very quickly. To mitigate this, you should schedule[/docs/{{version}}/scheduling] the queue:prune-batches
Artisan command to run daily:
use Illuminate\Support\Facades\Schedule;
Schedule::command('queue:prune-batches')->daily();
デフォルトでは、完了してから24時間以上経過したすべてのバッチが整理されます。バッチデータを保持する時間を決定するためにコマンド呼び出し時にhours
オプションを使用できます。たとえば、次のコマンドは48時間以上前に終了したすべてのバッチを削除します。By default, all finished batches that are more than 24 hours old will be pruned. You may use the hours
option when calling the command to determine how long to retain batch data. For example, the following command will delete all batches that finished over 48 hours ago:
use Illuminate\Support\Facades\Schedule;
Schedule::command('queue:prune-batches --hours=48')->daily();
時々、jobs_batches
テーブルに、ジョブが失敗して再試行も成功しなかったバッチなど、正常に完了しなかったバッチのバッチレコードが蓄積されることがあります。queue:prune-batches
コマンドでunfinished
オプションを使って、こうした未完了のバッチレコードを削除するように指示できます。Sometimes, your jobs_batches
table may accumulate batch records for batches that never completed successfully, such as batches where a job failed and that job was never retried successfully. You may instruct the queue:prune-batches
command to prune these unfinished batch records using the unfinished
option:
use Illuminate\Support\Facades\Schedule;
Schedule::command('queue:prune-batches --hours=48 --unfinished=72')->daily();
jobs_batches
テーブルと同様に、キャンセルされたバッチレコードが蓄積されるかもしれません。queue:prune-batches
コマンドのcancelled
オプションを使って、これらのキャンセルされたバッチレコードを整理ように指示してください。Likewise, your jobs_batches
table may also accumulate batch records for cancelled batches. You may instruct the queue:prune-batches
command to prune these cancelled batch records using the cancelled
option:
use Illuminate\Support\Facades\Schedule;
Schedule::command('queue:prune-batches --hours=48 --cancelled=72')->daily();
DynamoDBへのバッチ保存Storing Batches in DynamoDB
Laravelでは、バッチのメタ情報をリレーショナルデータベースではなく、DynamoDBへ格納する方法もサポートしています。ただし、バッチレコードをすべて格納する、DynamoDBテーブルを手作業で作成する必要があります。Laravel also provides support for storing batch meta information in DynamoDB[https://aws.amazon.com/dynamodb] instead of a relational database. However, you will need to manually create a DynamoDB table to store all of the batch records.
通常、このテーブルはjob_batches
という名前にしますが、アプリケーションのqueue
設定ファイル内のqueue.batching.table
設定値に基づいて名前を付ける必要があります。Typically, this table should be named job_batches
, but you should name the table based on the value of the queue.batching.table
configuration value within your application's queue
configuration file.
DynamoDBバッチテーブル設定DynamoDB Batch Table Configuration
job_batches
テーブルには、application
という文字列のプライマリパーティションキーとid
という文字列のプライマリソートキーを設定してください。キーのapplication
の部分には、アプリケーションのapp
設定ファイル内のname
設定値で定義したアプリケーション名が格納されます。アプリケーション名はDynamoDBテーブルのキーの一部なので、同じテーブルを使って複数のLaravelアプリケーションのジョブバッチを格納できます。The job_batches
table should have a string primary partition key named application
and a string primary sort key named id
. The application
portion of the key will contain your application's name as defined by the name
configuration value within your application's app
configuration file. Since the application name is part of the DynamoDB table's key, you can use the same table to store job batches for multiple Laravel applications.
さらに、自動バッチ整理を利用したい場合は、テーブルにttl
属性を定義することもできます。In addition, you may define ttl
attribute for your table if you would like to take advantage of automatic batch pruning[#pruning-batches-in-dynamodb].
DynamoDB設定DynamoDB Configuration
次に、LaravelアプリケーションがAmazon DynamoDBと通信できるように、AWS SDKをインストールします。Next, install the AWS SDK so that your Laravel application can communicate with Amazon DynamoDB:
composer require aws/aws-sdk-php
次に、queue.batching.driver
設定オプションの値をdynamodb
に設定します。さらに、batching
設定配列内で、key
、secret
、region
設定オプションを定義してください。これらのオプションはAWSとの認証に使用します。dynamodb
ドライバを使用する場合、queue.batching.database
設定オプションは不要です。Then, set the queue.batching.driver
configuration option's value to dynamodb
. In addition, you should define key
, secret
, and region
configuration options within the batching
configuration array. These options will be used to authenticate with AWS. When using the dynamodb
driver, the queue.batching.database
configuration option is unnecessary:
'batching' => [
'driver' => env('QUEUE_BATCHING_DRIVER', 'dynamodb'),
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
'table' => 'job_batches',
],
DynamoDBでのバッチの整理Pruning Batches in DynamoDB
DynamoDBを使用してジョブバッチ情報を保存する場合、リレーショナルデータベースへ保存したバッチを削除する、一般的なコマンドは機能しません。代わりに、DynamoDBのネイティブTTL機能を利用して、古いバッチのレコードを自動的に削除できます。When utilizing DynamoDB[https://aws.amazon.com/dynamodb] to store job batch information, the typical pruning commands used to prune batches stored in a relational database will not work. Instead, you may utilize DynamoDB's native TTL functionality[https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html] to automatically remove records for old batches.
DynamoDBのテーブルにttl
属性を定義した場合、Laravelにバッチレコードの整理方法を指示する設定パラメータを定義できます。queue.batching.ttl_attribute
設定値はTTLを保持する属性名を定義し、queue.batching.ttl
設定値は、最後に更新されてからバッチレコードがDynamoDBテーブルから削除されるまでの秒数を定義します。If you defined your DynamoDB table with a ttl
attribute, you may define configuration parameters to instruct Laravel how to prune batch records. The queue.batching.ttl_attribute
configuration value defines the name of the attribute holding the TTL, while the queue.batching.ttl
configuration value defines the number of seconds after which a batch record can be removed from the DynamoDB table, relative to the last time the record was updated:
'batching' => [
'driver' => env('QUEUE_FAILED_DRIVER', 'dynamodb'),
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
'table' => 'job_batches',
'ttl_attribute' => 'ttl',
'ttl' => 60 * 60 * 24 * 7, // 7日
],
クロージャのキュー投入Queueing Closures
ジョブクラスをキューにディスパッチする代わりに、クロージャをディスパッチすることもできます。これは、現在のリクエストサイクルの外で実行する必要がある迅速で単純なタスクに最適です。クロージャをキューにディスパッチする場合、クロージャのコードコンテンツは暗号で署名されているため、転送中に変更することはできません。Instead of dispatching a job class to the queue, you may also dispatch a closure. This is great for quick, simple tasks that need to be executed outside of the current request cycle. When dispatching closures to the queue, the closure's code content is cryptographically signed so that it cannot be modified in transit:
$podcast = App\Podcast::find(1);
dispatch(function () use ($podcast) {
$podcast->publish();
});
catch
メソッドを使用して、キューで設定した再試行をすべて使い果たしても、キュー投入したクロージャが正常に完了しなかった場合に実行する必要があるクロージャを提供できます。Using the catch
method, you may provide a closure that should be executed if the queued closure fails to complete successfully after exhausting all of your queue's configured retry attempts[#max-job-attempts-and-timeout]:
use Throwable;
dispatch(function () use ($podcast) {
$podcast->publish();
})->catch(function (Throwable $e) {
// このジョブは失敗
});
Warning!
catch
コールバックはシリアライズされ、Laravel のキューにより後ほど実行されるため、catch
コールバック内で$this
変数を使用するべきではありません。[!WARNING]
Sincecatch
callbacks are serialized and executed at a later time by the Laravel queue, you should not use the$this
variable withincatch
callbacks.
キューワーカの実行Running the Queue Worker
queue:work
コマンドThe queue:work
Command
Laravelは、キューワーカを開始し、キューに投入された新しいジョブを処理するArtisanコマンドを用意しています。queue:work
Artisanコマンドを使用してワーカを実行します。queue:work
コマンドを開始すると、手作業で停止するか、ターミナルを閉じるまで実行され続けることに注意してください。Laravel includes an Artisan command that will start a queue worker and process new jobs as they are pushed onto the queue. You may run the worker using the queue:work
Artisan command. Note that once the queue:work
command has started, it will continue to run until it is manually stopped or you close your terminal:
php artisan queue:work
Note:
queue:work
プロセスをバックグラウンドで永続的に実行し続けるには、Supervisorなどのプロセスモニタを使用して、キューワーカの実行が停止しないようにする必要があります。[!NOTE]
To keep thequeue:work
process running permanently in the background, you should use a process monitor such as Supervisor[#supervisor-configuration] to ensure that the queue worker does not stop running.
処理済みのジョブIDをコマンド出力へ含めたい場合は、queue:work
コマンドを実行する際に、-v
フラグを指定します。You may include the -v
flag when invoking the queue:work
command if you would like the processed job IDs to be included in the command's output:
php artisan queue:work -v
キューワーカは長期間有効なプロセスであり、起動した時点のアプリケーションの状態をメモリに保存することを忘れないでください。その結果、起動後にコードベースの変更に気付くことはありません。したがって、デプロイメントプロセス中で、必ずキューワーカを再起動してください。さらに、アプリケーションによって作成または変更された静的状態は、ジョブ間で自動的にリセットされないことに注意してください。Remember, queue workers are long-lived processes and store the booted application state in memory. As a result, they will not notice changes in your code base after they have been started. So, during your deployment process, be sure to restart your queue workers[#queue-workers-and-deployment]. In addition, remember that any static state created or modified by your application will not be automatically reset between jobs.
もしくは、queue:listen
コマンドを実行することもできます。queue:listen
コマンドを使用する場合、更新されたコードをリロードしたり、アプリケーションの状態をリセットしたりするときに、ワーカを手作業で再起動する必要はありません。ただし、このコマンドはqueue:work
コマンドよりも大幅に効率が低くなります。Alternatively, you may run the queue:listen
command. When using the queue:listen
command, you don't have to manually restart the worker when you want to reload your updated code or reset the application state; however, this command is significantly less efficient than the queue:work
command:
php artisan queue:listen
複数のキューワーカの実行Running Multiple Queue Workers
複数のワーカをキューへ割り当ててジョブを同時に処理するには、複数のqueue:work
プロセスを開始するだけです。これは、ターミナルの複数のタブを介してローカルで実行することも、プロセスマネージャの設定設定を使用して本番環境で実行することもできます。スーパーバイザーを使用する場合、numprocs
設定値が使用できます。To assign multiple workers to a queue and process jobs concurrently, you should simply start multiple queue:work
processes. This can either be done locally via multiple tabs in your terminal or in production using your process manager's configuration settings. When using Supervisor[#supervisor-configuration], you may use the numprocs
configuration value.
接続とキューの指定Specifying the Connection and Queue
ワーカが使用するキュー接続を指定することもできます。work
コマンドに渡される接続名は、config/queue.php
設定ファイルで定義されている接続の1つに対応している必要があります。You may also specify which queue connection the worker should utilize. The connection name passed to the work
command should correspond to one of the connections defined in your config/queue.php
configuration file:
php artisan queue:work redis
デフォルトでqueue:work
コマンドは、指定された接続のデフォルトキューのジョブのみを処理します。しかしながら、指定する接続で特定のキューのみを処理することで、キューワーカをさらにカスタマイズできます。たとえば、すべてのメールをredis
キュー接続のemails
キューで処理する場合、次のコマンドを発行して、そのキューのみを処理するワーカを起動できます。By default, the queue:work
command only processes jobs for the default queue on a given connection. However, you may customize your queue worker even further by only processing particular queues for a given connection. For example, if all of your emails are processed in an emails
queue on your redis
queue connection, you may issue the following command to start a worker that only processes that queue:
php artisan queue:work redis --queue=emails
指定数ジョブの処理Processing a Specified Number of Jobs
--once
オプションを使用して、キューから1つのジョブのみを処理するようにワーカに指示できます。The --once
option may be used to instruct the worker to only process a single job from the queue:
php artisan queue:work --once
--max-jobs
オプションを使用して、指定する数のジョブを処理してから終了するようにワーカに指示できます。このオプションは、Supervisorと組み合わせると便利な場合があります。これにより、ワーカは、指定する数のジョブを処理した後に自動的に再起動され、蓄積された可能性のあるメモリが解放されます。The --max-jobs
option may be used to instruct the worker to process the given number of jobs and then exit. This option may be useful when combined with Supervisor[#supervisor-configuration] so that your workers are automatically restarted after processing a given number of jobs, releasing any memory they may have accumulated:
php artisan queue:work --max-jobs=1000
キュー投入したすべてのジョブを処理後に終了Processing All Queued Jobs and Then Exiting
--stop-when-empty
オプションを使用して、すべてのジョブを処理してから正常に終了するようにワーカに指示できます。このオプションは、Dockerコンテナ内のLaravelキューを処理するときに、キューが空になった後にコンテナをシャットダウンする場合に役立ちます。The --stop-when-empty
option may be used to instruct the worker to process all jobs and then exit gracefully. This option can be useful when processing Laravel queues within a Docker container if you wish to shutdown the container after the queue is empty:
php artisan queue:work --stop-when-empty
Processing Jobs for a Given Number of SecondsProcessing Jobs for a Given Number of Seconds
--max-time
オプションを使用して、指定する秒数の間ジョブを処理してから終了するようにワーカに指示できます。このオプションは、Supervisorと組み合わせると便利な場合があります。これにより、ジョブを一定時間処理した後、ワーカが自動的に再起動され、蓄積された可能性のあるメモリが解放されます。The --max-time
option may be used to instruct the worker to process jobs for the given number of seconds and then exit. This option may be useful when combined with Supervisor[#supervisor-configuration] so that your workers are automatically restarted after processing jobs for a given amount of time, releasing any memory they may have accumulated:
# Process jobs for one hour and then exit...
php artisan queue:work --max-time=3600
ワーカのスリープ期間Worker Sleep Duration
キューにジョブが現れると、ワーカはジョブの処理を遅延なく処理し続けます。しかし、sleep
オプションを指定する場合、利用可能なジョブがない場合、ワーカは指定秒数間「スリープ」します。もちろん、スリープ中はワーカーは新しいジョブを処理しません。When jobs are available on the queue, the worker will keep processing jobs with no delay in between jobs. However, the sleep
option determines how many seconds the worker will "sleep" if there are no jobs available. Of course, while sleeping, the worker will not process any new jobs:
php artisan queue:work --sleep=3
メンテナンスモードとキューMaintenance Mode and Queues
アプリケーションがメンテナンスモードの間は、キューへ投入したジョブを処理しません。アプリケーションのメンテナンスモードが解除されると、通常通りジョブを処理します。While your application is in maintenance mode[/docs/{{version}}/configuration#maintenance-mode], no queued jobs will be handled. The jobs will continue to be handled as normal once the application is out of maintenance mode.
メンテナンスモードが有効になっていても、キューワーカにジョブを処理させるには、--force
オプションを使用します:To force your queue workers to process jobs even if maintenance mode is enabled, you may use --force
option:
php artisan queue:work --force
リソースに関する検討事項Resource Considerations
デーモンキューワーカは、各ジョブを処理する前にフレームワークを「再起動」しません。したがって、各ジョブが完了した後、重いリソースを解放する必要があります。たとえば、GDライブラリを使用して画像操作を行っている場合は、画像の処理が完了したら、imagedestroy
を使用してメモリを解放する必要があります。Daemon queue workers do not "reboot" the framework before processing each job. Therefore, you should release any heavy resources after each job completes. For example, if you are doing image manipulation with the GD library, you should free the memory with imagedestroy
when you are done processing the image.
キューの優先度Queue Priorities
キューの処理方法に優先順位を付けたい場合があります。たとえば、config/queue.php
設定ファイルで、デフォルトqueue
をredis
接続のlow
に設定できます。ただし、次のように、ジョブをhigh
優先度キューに投入したい場合もあるでしょう。Sometimes you may wish to prioritize how your queues are processed. For example, in your config/queue.php
configuration file, you may set the default queue
for your redis
connection to low
. However, occasionally you may wish to push a job to a high
priority queue like so:
dispatch((new Job)->onQueue('high'));
low
キューのジョブを続行する前に、すべてのhigh
キュージョブが処理されていることを確認するワーカを開始するには、キュー名のコンマ区切りリストをwork
コマンドに渡します。To start a worker that verifies that all of the high
queue jobs are processed before continuing to any jobs on the low
queue, pass a comma-delimited list of queue names to the work
command:
php artisan queue:work --queue=high,low
キューワーカと開発Queue Workers and Deployment
キューワーカは存続期間の長いプロセスであるため、再起動しない限り、コードの変更が反映されることはありません。したがって、キューワーカを使用してアプリケーションをデプロイする最も簡単な方法は、デプロイメントプロセス中にワーカを再起動することです。queue:restart
コマンドを発行することにより、すべてのワーカを正常に再起動できます。Since queue workers are long-lived processes, they will not notice changes to your code without being restarted. So, the simplest way to deploy an application using queue workers is to restart the workers during your deployment process. You may gracefully restart all of the workers by issuing the queue:restart
command:
php artisan queue:restart
このコマンドは、既存のジョブが失われないように、現在のジョブの処理が終了した後、すべてのキューワーカに正常に終了するように指示します。queue:restart
コマンドを実行するとキューワーカが終了するため、Supervisorなどのプロセスマネージャを実行して、キューワーカを自動的に再起動する必要があります。This command will instruct all queue workers to gracefully exit after they finish processing their current job so that no existing jobs are lost. Since the queue workers will exit when the queue:restart
command is executed, you should be running a process manager such as Supervisor[#supervisor-configuration] to automatically restart the queue workers.
キャッシュを使用して再起動シグナルを保存するため、この機能を使用する前に、アプリケーションに対してキャッシュドライバが適切に設定されていることを確認する必要があります。[!NOTE]
Note: キューは
The queue uses the cache[/docs/{{version}}/cache] to store restart signals, so you should verify that a cache driver is properly configured for your application before using this feature.
ジョブの有効期限とタイムアウトJob Expirations and Timeouts
ジョブの有効期限Job Expiration
config/queue.php
設定ファイルで、各キュー接続ごとにretry_after
オプションが定義されています。このオプションは、処理中のジョブを再試行する前にキュー接続が待機する秒数を指定します。たとえば、retry_after
の値が90
に設定されている場合、ジョブが解放または削除されずに90秒間処理されていれば、ジョブはキューに解放されます。通常、retry_after
値は、ジョブが処理を完了するのに合理的にかかる最大秒数に設定する必要があります。In your config/queue.php
configuration file, each queue connection defines a retry_after
option. This option specifies how many seconds the queue connection should wait before retrying a job that is being processed. For example, if the value of retry_after
is set to 90
, the job will be released back onto the queue if it has been processing for 90 seconds without being released or deleted. Typically, you should set the retry_after
value to the maximum number of seconds your jobs should reasonably take to complete processing.
Warning!
retry_after
値を含まない唯一のキュー接続はAmazon SQSです。SQSは、AWSコンソール内で管理しているDefault Visibility Timeoutに基づいてジョブを再試行します。[!WARNING]
The only queue connection which does not contain aretry_after
value is Amazon SQS. SQS will retry the job based on the Default Visibility Timeout[https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/AboutVT.html] which is managed within the AWS console.
ワーカタイムアウトWorker Timeouts
queue:work
Artisanコマンドは--timeout
オプションを用意しています。--timeout
のデフォルト値は60秒です。ジョブがタイムアウト値で指定する秒数より長く処理されている場合、ジョブを処理しているワーカはエラーで終了します。通常、ワーカはサーバで構築済みのプロセスマネージャによって自動的に再起動されます。The queue:work
Artisan command exposes a --timeout
option. By default, the --timeout
value is 60 seconds. If a job is processing for longer than the number of seconds specified by the timeout value, the worker processing the job will exit with an error. Typically, the worker will be restarted automatically by a process manager configured on your server[#supervisor-configuration]:
php artisan queue:work --timeout=60
retry_after
設定オプションと--timeout
CLIオプションは異なりますが、ジョブが失われないように、またジョブが1回だけ正常に処理されるように連携して機能します。The retry_after
configuration option and the --timeout
CLI option are different, but work together to ensure that jobs are not lost and that jobs are only successfully processed once.
Warning!
--timeout
値は、常にretry_after
設定値より少なくとも数秒短くする必要があります。これにより、フリーズしたジョブを処理しているワーカは、ジョブが再試行される前に常に終了します。--timeout
オプションがretry_after
設定値よりも長い場合、ジョブは2回処理される可能性があります。[!WARNING]
The--timeout
value should always be at least several seconds shorter than yourretry_after
configuration value. This will ensure that a worker processing a frozen job is always terminated before the job is retried. If your--timeout
option is longer than yourretry_after
configuration value, your jobs may be processed twice.
Supervisor設定Supervisor Configuration
本番環境では、queue:work
プロセスを実行し続ける手段が必要です。queue:work
プロセスは、ワーカタイムアウトの超過や、queue:restart
コマンドの実行など、さまざまな理由で実行を停止する場合があります。In production, you need a way to keep your queue:work
processes running. A queue:work
process may stop running for a variety of reasons, such as an exceeded worker timeout or the execution of the queue:restart
command.
このため、queue:work
プロセスが終了したことを検出し、自動的に再起動できるプロセスモニタを構築する必要があります。さらに、プロセスモニタを使用すると、同時に実行するqueue:work
プロセスの数を指定できます。Supervisorは、Linux環境で一般的に使用されるプロセスモニタであり、以下のドキュメントでその設定方法について説明します。For this reason, you need to configure a process monitor that can detect when your queue:work
processes exit and automatically restart them. In addition, process monitors can allow you to specify how many queue:work
processes you would like to run concurrently. Supervisor is a process monitor commonly used in Linux environments and we will discuss how to configure it in the following documentation.
SupervisorのインストールInstalling Supervisor
SupervisorはLinuxオペレーティングシステムのプロセスモニターであり、落ちた場合にqueue:work
プロセスを自動的に再起動します。UbuntuにSupervisorをインストールするには、次のコマンドを使用します。Supervisor is a process monitor for the Linux operating system, and will automatically restart your queue:work
processes if they fail. To install Supervisor on Ubuntu, you may use the following command:
sudo apt-get install supervisor
Laravel Forgeの使用を検討してください。これにより、本番LaravelプロジェクトのSupervisorが自動的にインストールおよび設定されます。[!NOTE]
Note: 自分でSupervisorを設定および管理するのが難しいと思われる場合は、
If configuring and managing Supervisor yourself sounds overwhelming, consider using Laravel Forge[https://forge.laravel.com], which will automatically install and configure Supervisor for your production Laravel projects.
Supervisorの設定Configuring Supervisor
Supervisor設定ファイルは通常、/etc/supervisor/conf.d
ディレクトリに保管されます。このディレクトリ内に、プロセスの監視方法をSupervisorに指示する設定ファイルをいくつでも作成できます。たとえば、queue:work
プロセスを開始および監視するlaravel-worker.conf
ファイルを作成してみましょう。Supervisor configuration files are typically stored in the /etc/supervisor/conf.d
directory. Within this directory, you may create any number of configuration files that instruct supervisor how your processes should be monitored. For example, let's create a laravel-worker.conf
file that starts and monitors queue:work
processes:
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /home/forge/app.com/artisan queue:work sqs --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=forge
numprocs=8
redirect_stderr=true
stdout_logfile=/home/forge/app.com/worker.log
stopwaitsecs=3600
この例中のnumprocs
ディレクティブは、スーパーバイザーへ8つのqueue:work
プロセスを実行し、それらすべてを監視し、失敗した場合は自動的に再起動するように指示します。必要なキュー接続とワーカオプションを反映するように、設定のcommand
ディレクティブを変更する必要があります。In this example, the numprocs
directive will instruct Supervisor to run eight queue:work
processes and monitor all of them, automatically restarting them if they fail. You should change the command
directive of the configuration to reflect your desired queue connection and worker options.
Warning!
stopwaitsecs
の値が、最も長く実行されるジョブが消費する秒数よりも大きいことを確認する必要があります。そうしないと、Supervisorは処理が完了する前にジョブを強制終了する可能性があります。[!WARNING]
You should ensure that the value ofstopwaitsecs
is greater than the number of seconds consumed by your longest running job. Otherwise, Supervisor may kill the job before it is finished processing.
Supervisorの起動Starting Supervisor
設定ファイルを作成したら、以下のコマンドを使用して、Supervisor設定を更新し、プロセスを開始できます。Once the configuration file has been created, you may update the Supervisor configuration and start the processes using the following commands:
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start "laravel-worker:*"
Supervisorの詳細は、Supervisorのドキュメントを参照してください。For more information on Supervisor, consult the Supervisor documentation[http://supervisord.org/index.html].
失敗したジョブの処理Dealing With Failed Jobs
キュー投入したジョブは、失敗することがあります。心配いりません。物事は常に計画通りに進むわけではありません。Laravelには、ジョブを試行する最大回数を指定する便利な方法があります。非同期ジョブがこの試行回数を超えると、そのジョブはfailed_jobs
データベーステーブルに挿入されます。同期的にディスパッチするジョブは失敗してもこのテーブルへ格納せず、その例外は直ちにアプリケーションにより処理されます。Sometimes your queued jobs will fail. Don't worry, things don't always go as planned! Laravel includes a convenient way to specify the maximum number of times a job should be attempted[#max-job-attempts-and-timeout]. After an asynchronous job has exceeded this number of attempts, it will be inserted into the failed_jobs
database table. Synchronously dispatched jobs[/docs/{{version}}/queues#synchronous-dispatching] that fail are not stored in this table and their exceptions are immediately handled by the application.
failed_jobs
テーブルを作成するマイグレーションは、通常、新しいLaravelアプリケーションにはあらかじめ存在しています。しかし、アプリケーションにこのテーブルのマイグレーションが含まれていない場合は、make:queue-failed-table
コマンドを使い作成できます。A migration to create the failed_jobs
table is typically already present in new Laravel applications. However, if your application does not contain a migration for this table, you may use the make:queue-failed-table
command to create the migration:
php artisan make:queue-failed-table
php artisan migrate
キューワーカプロセスを実行する場合、queue:work
コマンドの--tries
スイッチを使用してジョブを試行する最大回数を指定できます。--tries
オプションの値を指定しない場合、ジョブは1回だけ、またはジョブクラスの$tries
プロパティで指定する回数だけ試行されます。When running a queue worker[#running-the-queue-worker] process, you may specify the maximum number of times a job should be attempted using the --tries
switch on the queue:work
command. If you do not specify a value for the --tries
option, jobs will only be attempted once or as many times as specified by the job class' $tries
property:
php artisan queue:work redis --tries=3
--backoff
オプションを使用して、例外が発生したジョブを再試行する前にLaravelが待機する秒数を指定できます。デフォルトでは、ジョブはすぐにキューに戻され、再試行されます。Using the --backoff
option, you may specify how many seconds Laravel should wait before retrying a job that has encountered an exception. By default, a job is immediately released back onto the queue so that it may be attempted again:
php artisan queue:work redis --tries=3 --backoff=3
例外が発生したジョブを再試行する前にLaravelが待機する秒数をジョブごとに設定したい場合は、ジョブクラスにbackoff
プロパティを定義することで設定できます。If you would like to configure how many seconds Laravel should wait before retrying a job that has encountered an exception on a per-job basis, you may do so by defining a backoff
property on your job class:
/**
* ジョブを再試行する前に待機する秒数
*
* @var int
*/
public $backoff = 3;
ジョブのバックオフ時間を決定するために複雑なロジックが必要な場合は、ジョブクラスでbackoff
メソッドを定義します。If you require more complex logic for determining the job's backoff time, you may define a backoff
method on your job class:
/**
* ジョブを再試行する前に待機する秒数を計算
*/
public function backoff(): int
{
return 3;
}
backoff
メソッドからバックオフ値の配列を返すことで、「指数」バックオフを簡単に設定できます。この例では、再試行の遅延は最初の最初の再試行で1秒、2回目の再試行で5秒、3回目の再試行で10秒、それ以降も再試行が残っている場合は毎回10秒となります:You may easily configure "exponential" backoffs by returning an array of backoff values from the backoff
method. In this example, the retry delay will be 1 second for the first retry, 5 seconds for the second retry, 10 seconds for the third retry, and 10 seconds for every subsequent retry if there are more attempts remaining:
/**
* ジョブを再試行する前に待機する秒数を計算
*
* @return array<int, int>
*/
public function backoff(): array
{
return [1, 5, 10];
}
ジョブ失敗後の片付けCleaning Up After Failed Jobs
特定のジョブが失敗した場合、ユーザーにアラートを送信するか、ジョブによって部分的に完了したアクションを元に戻すことができます。これを実現するために、ジョブクラスでfailed
メソッドを定義できます。ジョブの失敗の原因となったThrowable
インスタンスは、failed
メソッドへ渡されます。When a particular job fails, you may want to send an alert to your users or revert any actions that were partially completed by the job. To accomplish this, you may define a failed
method on your job class. The Throwable
instance that caused the job to fail will be passed to the failed
method:
<?php
namespace App\Jobs;
use App\Models\Podcast;
use App\Services\AudioProcessor;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Throwable;
class ProcessPodcast implements ShouldQueue
{
use Queueable;
/**
* 新しいジョブインスタンスの生成
*/
public function __construct(
public Podcast $podcast,
) {}
/**
* ジョブの実行
*/
public function handle(AudioProcessor $processor): void
{
// アップロードされたポッドキャストを処理…
}
/**
* ジョブの失敗を処理
*/
public function failed(?Throwable $exception): void
{
// ユーザーへ失敗を通知するなど…
}
}
Warning!
failed
メソッドを呼び出す前に、ジョブが新しくインスタンス化されます。したがって、handle
メソッド内で発生した可能性があるクラスプロパティの変更は失われます。[!WARNING]
A new instance of the job is instantiated before invoking thefailed
method; therefore, any class property modifications that may have occurred within thehandle
method will be lost.
失敗したジョブの再試行Retrying Failed Jobs
failed_jobs
データベーステーブルに挿入されたすべての失敗したジョブを表示するには、queue:failed
Artisanコマンドを使用します。To view all of the failed jobs that have been inserted into your failed_jobs
database table, you may use the queue:failed
Artisan command:
php artisan queue:failed
queue:failed
コマンドは、ジョブID、接続、キュー、失敗時間、およびジョブに関するその他の情報を一覧表示します。ジョブIDは、失敗したジョブを再試行するために使用できます。たとえば、IDがce7bb17c-cdd8-41f0-a8ec-7b4fef4e5ece
の失敗したジョブを再試行するには、次のコマンドを発行します。The queue:failed
command will list the job ID, connection, queue, failure time, and other information about the job. The job ID may be used to retry the failed job. For instance, to retry a failed job that has an ID of ce7bb17c-cdd8-41f0-a8ec-7b4fef4e5ece
, issue the following command:
php artisan queue:retry ce7bb17c-cdd8-41f0-a8ec-7b4fef4e5ece
必要に応じ、複数のIDをコマンドへ渡せます。If necessary, you may pass multiple IDs to the command:
php artisan queue:retry ce7bb17c-cdd8-41f0-a8ec-7b4fef4e5ece 91401d2c-0784-4f43-824c-34f94a33c24d
指定するキューの失敗したジョブをすべて再試行することもできます。You may also retry all of the failed jobs for a particular queue:
php artisan queue:retry --queue=name
失敗したすべてのジョブを再試行するには、queue:retry
コマンドを実行し、IDとしてall
を渡します。To retry all of your failed jobs, execute the queue:retry
command and pass all
as the ID:
php artisan queue:retry all
失敗したジョブを削除したい場合は、queue:forget
コマンドを使用します。If you would like to delete a failed job, you may use the queue:forget
command:
php artisan queue:forget 91401d2c-0784-4f43-824c-34f94a33c24d
Horizonを使用する場合は、
Note:queue:forget
コマンドの代わりにhorizon:forget
コマンドを使用して失敗したジョブを削除する必要があります。[!NOTE]
When using Horizon[/docs/{{version}}/horizon], you should use thehorizon:forget
command to delete a failed job instead of thequeue:forget
command.
失敗したすべてのジョブをfailed_jobs
テーブルから削除するには、queue:flush
コマンドを使用します。To delete all of your failed jobs from the failed_jobs
table, you may use the queue:flush
command:
php artisan queue:flush
見つからないモデルの無視Ignoring Missing Models
Eloquentモデルをジョブに挿入すると、モデルは自動的にシリアル化されてからキューに配置され、ジョブの処理時にデータベースから再取得されます。ただし、ジョブがワーカによる処理を待機している間にモデルが削除された場合、ジョブはModelNotFoundException
で失敗する可能性があります。When injecting an Eloquent model into a job, the model is automatically serialized before being placed on the queue and re-retrieved from the database when the job is processed. However, if the model has been deleted while the job was waiting to be processed by a worker, your job may fail with a ModelNotFoundException
.
利便性のため、ジョブのdeleteWhenMissingModels
プロパティをtrue
に設定することで、モデルが見つからないジョブを自動的に削除できます。このプロパティがtrue
に設定されている場合、Laravelは例外を発生させることなく静かにジョブを破棄します。For convenience, you may choose to automatically delete jobs with missing models by setting your job's deleteWhenMissingModels
property to true
. When this property is set to true
, Laravel will quietly discard the job without raising an exception:
/**
* モデルが存在しなくなった場合は、ジョブを削除
*
* @var bool
*/
public $deleteWhenMissingModels = true;
失敗したジョブの切り詰めPruning Failed Jobs
アプリケーションのfailed_jobs
テーブルのレコードを切り詰めるには、queue:prune-failed
Artisanコマンドを実行します。You may prune the records in your application's failed_jobs
table by invoking the queue:prune-failed
Artisan command:
php artisan queue:prune-failed
デフォルトでは、24時間以上前の失敗したジョブの記録をすべて切り捨てます。コマンドに--hours
オプションを指定すると、直近のN時間以内に挿入された、失敗したジョブ記録のみを保持します。たとえば、次のコマンドは48時間以上前に挿入された、失敗したジョブのレコードをすべて削除します。By default, all the failed job records that are more than 24 hours old will be pruned. If you provide the --hours
option to the command, only the failed job records that were inserted within the last N number of hours will be retained. For example, the following command will delete all the failed job records that were inserted more than 48 hours ago:
php artisan queue:prune-failed --hours=48
失敗したジョブのDynamoDBへの保存Storing Failed Jobs in DynamoDB
Laravelでは、失敗したジョブレコードをリレーショナルデータベースのテーブルではなく、DynamoDBへ保存するサポートも提供しています。ただし、失敗したジョブの記録をすべて保存するための、DynamoDBテーブルを手作業で作成しておく必要があります。通常、このテーブルはfailed_jobs
という名前になりますが、アプリケーションのqueue
設定ファイル内のqueue.failed.table
設定値に基づいて、テーブル名を付ける必要があります。Laravel also provides support for storing your failed job records in DynamoDB[https://aws.amazon.com/dynamodb] instead of a relational database table. However, you must manually create a DynamoDB table to store all of the failed job records. Typically, this table should be named failed_jobs
, but you should name the table based on the value of the queue.failed.table
configuration value within your application's queue
configuration file.
failed_jobs
テーブルは、application
という名前で文字列のプライマリパーティションキーと、uuid
という名前の文字列のプライマリソートキーを持つ必要があります。キーのapplication
部分には、アプリケーションのapp
設定ファイル内のname
設定値で定義したアプリケーション名が含まれます。アプリケーション名はDynamoDBテーブルのキーの一部なので、同じテーブルを使って複数のLaravelアプリケーションの失敗したジョブを保存できます。The failed_jobs
table should have a string primary partition key named application
and a string primary sort key named uuid
. The application
portion of the key will contain your application's name as defined by the name
configuration value within your application's app
configuration file. Since the application name is part of the DynamoDB table's key, you can use the same table to store failed jobs for multiple Laravel applications.
さらに、LaravelアプリケーションがAmazon DynamoDBと通信できるように、AWS SDKを確実にインストールしてください。In addition, ensure that you install the AWS SDK so that your Laravel application can communicate with Amazon DynamoDB:
composer require aws/aws-sdk-php
次に、queue.failed.driver
設定オプションの値をdynamodb
に設定します。さらに、失敗したジョブの設定配列の中で、key
、secret
、region
の構成オプションを定義します。これらのオプションはAWSとの認証に使用されます。dynamodb
ドライバを使用する場合、queue.failed.database
設定オプションは不要です。Next, set the queue.failed.driver
configuration option's value to dynamodb
. In addition, you should define key
, secret
, and region
configuration options within the failed job configuration array. These options will be used to authenticate with AWS. When using the dynamodb
driver, the queue.failed.database
configuration option is unnecessary:
'failed' => [
'driver' => env('QUEUE_FAILED_DRIVER', 'dynamodb'),
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
'table' => 'failed_jobs',
],
失敗したジョブの保存の無効化Disabling Failed Job Storage
queue.failed.driver
設定オプションの値をnull
にすることで、失敗したジョブを保存せず、破棄するようにLaravelへ指示できます。通常、これはQUEUE_FAILED_DRIVER
環境変数の設定で実現します。You may instruct Laravel to discard failed jobs without storing them by setting the queue.failed.driver
configuration option's value to null
. Typically, this may be accomplished via the QUEUE_FAILED_DRIVER
environment variable:
QUEUE_FAILED_DRIVER=null
失敗したジョブイベントFailed Job Events
ジョブが失敗したときに呼び出されるイベントリスナを登録する場合は、Queue
ファサードのfailing
メソッドを使用できます。たとえば、Laravelに含まれているAppServiceProvider
のboot
メソッドからこのイベントにクロージャをアタッチできます。If you would like to register an event listener that will be invoked when a job fails, you may use the Queue
facade's failing
method. For example, we may attach a closure to this event from the boot
method of the AppServiceProvider
that is included with Laravel:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\ServiceProvider;
use Illuminate\Queue\Events\JobFailed;
class AppServiceProvider extends ServiceProvider
{
/**
* 全アプリケーションサービスの登録
*/
public function register(): void
{
// ...
}
/**
* 全アプリケーションサービスの初期起動処理
*/
public function boot(): void
{
Queue::failing(function (JobFailed $event) {
// $event->connectionName
// $event->job
// $event->exception
});
}
}
キューからのジョブクリアClearing Jobs From Queues
Horizonを使用する場合は、
Note:queue:clear
コマンドの代わりにhorizon:clear
コマンドを使用してキューからジョブをクリアする必要があります。[!NOTE]
When using Horizon[/docs/{{version}}/horizon], you should use thehorizon:clear
command to clear jobs from the queue instead of thequeue:clear
command.
デフォルト接続のデフォルトキューからすべてのジョブを削除する場合は、queue:clear
Artisanコマンドを使用して削除します。If you would like to delete all jobs from the default queue of the default connection, you may do so using the queue:clear
Artisan command:
php artisan queue:clear
特定の接続とキューからジョブを削除するために、connection
引数とqueue
オプションを指定することもできます。You may also provide the connection
argument and queue
option to delete jobs from a specific connection and queue:
php artisan queue:clear redis --queue=emails
[!WARNING]
Warning! キューからのジョブのクリアは、SQS、Redis、およびデータベースキュードライバでのみ使用できます。さらに、SQSメッセージの削除プロセスには最長60秒かかるため、キューをクリアしてから最長60秒後にSQSキューに送信されたジョブも削除される可能性があります。
Clearing jobs from queues is only available for the SQS, Redis, and database queue drivers. In addition, the SQS message deletion process takes up to 60 seconds, so jobs sent to the SQS queue up to 60 seconds after you clear the queue might also be deleted.
キューのモニタリングMonitoring Your Queues
キューにジョブが急激に投げ込まれると、過負荷になってしまい、ジョブが完了するまでの待ち時間が長くなってしまう可能性があります。お望みなら、Laravelはキューのジョブ数が特定の閾値を超えたときに警告を出すことができます。If your queue receives a sudden influx of jobs, it could become overwhelmed, leading to a long wait time for jobs to complete. If you wish, Laravel can alert you when your queue job count exceeds a specified threshold.
使い始めるなら、queue:monitor
コマンドを 毎分実行するようにスケジュールしてください。このコマンドには、監視したいキューの名前と、希望するジョブ数の閾値を指定します。To get started, you should schedule the queue:monitor
command to run every minute[/docs/{{version}}/scheduling]. The command accepts the names of the queues you wish to monitor as well as your desired job count threshold:
php artisan queue:monitor redis:default,redis:deployments --max=100
このコマンドをスケジューリングするだけでは、キューの過負荷状態を警告する通知をトリガするために十分ではありません。このコマンドが、閾値を超えたジョブ数のキューと遭遇すると、Illuminate\Queue\Events\QueueBusy
イベントをディスパッチします。あなたや開発チームに通知を送るために、アプリケーションのAppServiceProvider
内でこのイベントをリッスンしてください。Scheduling this command alone is not enough to trigger a notification alerting you of the queue's overwhelmed status. When the command encounters a queue that has a job count exceeding your threshold, an Illuminate\Queue\Events\QueueBusy
event will be dispatched. You may listen for this event within your application's AppServiceProvider
in order to send a notification to you or your development team:
use App\Notifications\QueueHasLongWaitTime;
use Illuminate\Queue\Events\QueueBusy;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Notification;
/**
* アプリケーションの全サービスの初期起動処理
*/
public function boot(): void
{
Event::listen(function (QueueBusy $event) {
Notification::route('mail', 'dev@example.com')
->notify(new QueueHasLongWaitTime(
$event->connection,
$event->queue,
$event->size
));
});
}
テストTesting
ジョブをディスパッチするコードをテストする場合、ジョブのコードはディスパッチするコードと別に、直接テストすることができるため、ジョブ自体を実際に実行しないようLaravelへ指示したい場合があるでしょう。もちろん、ジョブそのものをテストするために、ジョブインスタンスをインスタンス化し、テスト内でhandle
メソッドを直接呼び出すこともできます。When testing code that dispatches jobs, you may wish to instruct Laravel to not actually execute the job itself, since the job's code can be tested directly and separately of the code that dispatches it. Of course, to test the job itself, you may instantiate a job instance and invoke the handle
method directly in your test.
Queue
ファサードのfake
メソッドを使用すると、キュー投入したジョブを実際にキューへプッシュされないようにできます。Queue
ファサードのfake
メソッドを呼び出した後で、アプリケーションがジョブをキューへ投入しようとしたことをアサートできます。You may use the Queue
facade's fake
method to prevent queued jobs from actually being pushed to the queue. After calling the Queue
facade's fake
method, you may then assert that the application attempted to push jobs to the queue:
<?php
use App\Jobs\AnotherJob;
use App\Jobs\FinalJob;
use App\Jobs\ShipOrder;
use Illuminate\Support\Facades\Queue;
test('orders can be shipped', function () {
Queue::fake();
// 注文発送処理…
// ジョブが投入されないことをアサート
Queue::assertNothingPushed();
// 一つのジョブが指定キューへ投入されることをアサート
Queue::assertPushedOn('queue-name', ShipOrder::class);
// 一つのジョブが2回投入されることをアサート
Queue::assertPushed(ShipOrder::class, 2);
// 一つのジョブが投入されないことアサート
Queue::assertNotPushed(AnotherJob::class);
// クロージャがキューへ投入されることをアサート
Queue::assertClosurePushed();
// 投入されるジョブの合計数をアサート
Queue::assertCount(3);
});
<?php
namespace Tests\Feature;
use App\Jobs\AnotherJob;
use App\Jobs\FinalJob;
use App\Jobs\ShipOrder;
use Illuminate\Support\Facades\Queue;
use Tests\TestCase;
class ExampleTest extends TestCase
{
public function test_orders_can_be_shipped(): void
{
Queue::fake();
// 注文発送処理…
// ジョブが投入されないことをアサート
Queue::assertNothingPushed();
// 一つのジョブが指定キューへ投入されることをアサート
Queue::assertPushedOn('queue-name', ShipOrder::class);
// ジョブを2回投入することをアサート
Queue::assertPushed(ShipOrder::class, 2);
// 一つのジョブが投入されないことアサート
Queue::assertNotPushed(AnotherJob::class);
// クロージャがキューへ投入されることをアサート
Queue::assertClosurePushed();
// 投入されるジョブの合計数をアサート
Queue::assertCount(3);
}
}
指定する「真偽値テスト」にパスするジョブが、投入されたことをアサートするため、assertPushed
またはassertNotPushed
メソッドへクロージャを渡せます。指定真偽値テストにパスするジョブが最低一つ投入された場合、そのアサートをパスします。You may pass a closure to the assertPushed
or assertNotPushed
methods in order to assert that a job was pushed that passes a given "truth test". If at least one job was pushed that passes the given truth test then the assertion will be successful:
Queue::assertPushed(function (ShipOrder $job) use ($order) {
return $job->order->id === $order->id;
});
ジョブのサブセットのFakeFaking a Subset of Jobs
特定のジョブだけをFakeし、他のジョブは正常に実行させる必要がある場合は、fake
メソッドへ偽装するジョブのクラス名を渡してください。If you only need to fake specific jobs while allowing your other jobs to execute normally, you may pass the class names of the jobs that should be faked to the fake
method:
test('orders can be shipped', function () {
Queue::fake([
ShipOrder::class,
]);
// 注文発送処理…
// 一つのジョブが2回投入されることをアサート
Queue::assertPushed(ShipOrder::class, 2);
});
public function test_orders_can_be_shipped(): void
{
Queue::fake([
ShipOrder::class,
]);
// 注文発送処理…
// 一つのジョブが2回投入されることをアサート
Queue::assertPushed(ShipOrder::class, 2);
}
except
メソッドを使用すると、指定したジョブセット以外のすべてのジョブをFakeできます。You may fake all jobs except for a set of specified jobs using the except
method:
Queue::fake()->except([
ShipOrder::class,
]);
ジョブチェーンのテストTesting Job Chains
ジョブチェーンをテストするには、Bus
ファサードのFake機能を利用します。Bus
ファサードのassertChained
メソッドは、ジョブチェーンをディスパッチしたことをアサートするために使用します。assertChained
メソッドは、最初の引数にチェーンするジョブの配列を取ります。To test job chains, you will need to utilize the Bus
facade's faking capabilities. The Bus
facade's assertChained
method may be used to assert that a chain of jobs[/docs/{{version}}/queues#job-chaining] was dispatched. The assertChained
method accepts an array of chained jobs as its first argument:
use App\Jobs\RecordShipment;
use App\Jobs\ShipOrder;
use App\Jobs\UpdateInventory;
use Illuminate\Support\Facades\Bus;
Bus::fake();
// ...
Bus::assertChained([
ShipOrder::class,
RecordShipment::class,
UpdateInventory::class
]);
上の例でわかるように、ジョブチェーンの配列は、ジョブのクラス名の配列です。しかし、実際のジョブインスタンスの配列を指定することもできます。その場合、Laravelはジョブインスタンスが同じクラスであり、アプリケーションがディスパッチする同じジョブチェーンのプロパティ値を持つことを確認します。As you can see in the example above, the array of chained jobs may be an array of the job's class names. However, you may also provide an array of actual job instances. When doing so, Laravel will ensure that the job instances are of the same class and have the same property values of the chained jobs dispatched by your application:
Bus::assertChained([
new ShipOrder,
new RecordShipment,
new UpdateInventory,
]);
assertDispatchedWithoutChain
メソッドを使用すると、ジョブをチェーンせずに、投入したことをアサートできます。You may use the assertDispatchedWithoutChain
method to assert that a job was pushed without a chain of jobs:
Bus::assertDispatchedWithoutChain(ShipOrder::class);
チェーン変更のテストTesting Chain Modifications
チェーンしたジョブが、既存のチェーンへジョブを追加または前置きしている場合、ジョブのassertHasChain
メソッドを使って、そのジョブが期待通りの連鎖を持つことをアサートできます。If a chained job prepends or appends jobs to an existing chain[#adding-jobs-to-the-chain], you may use the job's assertHasChain
method to assert that the job has the expected chain of remaining jobs:
$job = new ProcessPodcast;
$job->handle();
$job->assertHasChain([
new TranscribePodcast,
new OptimizePodcast,
new ReleasePodcast,
]);
assertDoesntHaveChain
メソッドは、ジョブの残りのチェーンが空であることをアサートするために使用します。The assertDoesntHaveChain
method may be used to assert that the job's remaining chain is empty:
$job->assertDoesntHaveChain();
チェーンしたバッチのテストTesting Chained Batches
ジョブチェーンがジョブのバッチを含んでいる場合、チェーンのアサート内に Bus::chainedBatch
定義を挿入することにより、チェーンしたバッチが期待値にマッチしていることをアサートできます。If your job chain contains a batch of jobs[#chains-and-batches], you may assert that the chained batch matches your expectations by inserting a Bus::chainedBatch
definition within your chain assertion:
use App\Jobs\ShipOrder;
use App\Jobs\UpdateInventory;
use Illuminate\Bus\PendingBatch;
use Illuminate\Support\Facades\Bus;
Bus::assertChained([
new ShipOrder,
Bus::chainedBatch(function (PendingBatch $batch) {
return $batch->jobs->count() === 3;
}),
new UpdateInventory,
]);
ジョブバッチのテストTesting Job Batches
Bus
ファサードのassertBatched
メソッドは、ジョブのバッチを投入したことをアサートするために使用します。assertBatched
メソッドへ渡すクロージャは、Illuminate\Bus\PendingBatch
のインスタンスを引数に取り、バッチ内のジョブを検査するために使用できます。The Bus
facade's assertBatched
method may be used to assert that a batch of jobs[/docs/{{version}}/queues#job-batching] was dispatched. The closure given to the assertBatched
method receives an instance of Illuminate\Bus\PendingBatch
, which may be used to inspect the jobs within the batch:
use Illuminate\Bus\PendingBatch;
use Illuminate\Support\Facades\Bus;
Bus::fake();
// ...
Bus::assertBatched(function (PendingBatch $batch) {
return $batch->name == 'import-csv' &&
$batch->jobs->count() === 10;
});
assertBatchCount
メソッドを使い、指定数のバッチを投入したことをアサートできます。You may use the assertBatchCount
method to assert that a given number of batches were dispatched:
Bus::assertBatchCount(3);
assertNothingBatched
を使用し、バッチを投入していないことをアサートできます。You may use assertNothingBatched
to assert that no batches were dispatched:
Bus::assertNothingBatched();
ジョブ/バッチの相互操作のテストTesting Job / Batch Interaction
さらに、個々のジョブとその裏で動いているバッチとの、相互作用をテストする必要がある場合もあるでしょう。例えば、あるジョブがそのバッチの処理をキャンセルしたかをテストする必要があるかもしれません。これを実現するには、withFakeBatch
メソッドでFakeバッチをジョブに割り当てる必要があります。withFakeBatch
メソッドは、ジョブインスタンスとFakeバッチを含むタプルを返します。In addition, you may occasionally need to test an individual job's interaction with its underlying batch. For example, you may need to test if a job cancelled further processing for its batch. To accomplish this, you need to assign a fake batch to the job via the withFakeBatch
method. The withFakeBatch
method returns a tuple containing the job instance and the fake batch:
[$job, $batch] = (new ShipOrder)->withFakeBatch();
$job->handle();
$this->assertTrue($batch->cancelled());
$this->assertEmpty($batch->added);
ジョブ/キュー操作のテストTesting Job / Queue Interactions
時には、キュー投入したジョブがそれ自身をキューに戻すことをテストする必要が起きるかもしれません。あるいは、ジョブが自分自身を削除したことをテストする必要があるかもしれません。ジョブをインスタンス化してwithFakeQueueInteractions
メソッドを呼び出すことで、これらのキューとのやりとりをテストできます。Sometimes, you may need to test that a queued job releases itself back onto the queue[#manually-releasing-a-job]. Or, you may need to test that the job deleted itself. You may test these queue interactions by instantiating the job and invoking the withFakeQueueInteractions
method.
ジョブのキュー操作をFakeしたら、ジョブに対して handle
メソッドを呼び出してください。ジョブを呼び出した後は、assertReleased
、assertDeleted
、assertNotDeleted
、assertFailed
、assertNotFailed
メソッドを使用して、ジョブのキュー操作に対してアサートを行えます。Once the job's queue interactions have been faked, you may invoke the handle
method on the job. After invoking the job, the assertReleased
, assertDeleted
, assertNotDeleted
, assertFailed
, and assertNotFailed
methods may be used to make assertions against the job's queue interactions:
use App\Jobs\ProcessPodcast;
$job = (new ProcessPodcast)->withFakeQueueInteractions();
$job->handle();
$job->assertReleased(delay: 30);
$job->assertDeleted();
$job->assertNotDeleted();
$job->assertFailed();
$job->assertNotFailed();
ジョブイベントJob Events
Queue
ファサードのbefore
およびafter
メソッドを使用して、キュー投入したジョブが処理される前または後に実行するコールバックを指定できます。これらのコールバックは、ダッシュボードの追加のログまたは増分統計を実行する絶好の機会です。通常、これらのメソッドは、サービスプロバイダのboot
メソッドから呼び出す必要があります。たとえば、Laravelが用意しているAppServiceProvider
を使用できます。Using the before
and after
methods on the Queue
facade[/docs/{{version}}/facades], you may specify callbacks to be executed before or after a queued job is processed. These callbacks are a great opportunity to perform additional logging or increment statistics for a dashboard. Typically, you should call these methods from the boot
method of a service provider[/docs/{{version}}/providers]. For example, we may use the AppServiceProvider
that is included with Laravel:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\ServiceProvider;
use Illuminate\Queue\Events\JobProcessed;
use Illuminate\Queue\Events\JobProcessing;
class AppServiceProvider extends ServiceProvider
{
/**
* 全アプリケーションサービスの登録
*/
public function register(): void
{
// ...
}
/**
* 全アプリケーションサービスの初期起動処理
*/
public function boot(): void
{
Queue::before(function (JobProcessing $event) {
// $event->connectionName
// $event->job
// $event->job->payload()
});
Queue::after(function (JobProcessed $event) {
// $event->connectionName
// $event->job
// $event->job->payload()
});
}
}
Queue
ファサードでlooping
メソッドを使用して、ワーカがキューからジョブをフェッチしようとする前に実行するコールバックを指定できます。たとえば、クロージャを登録して、以前に失敗したジョブによって開いたままになっているトランザクションをロールバックすることができます。Using the looping
method on the Queue
facade[/docs/{{version}}/facades], you may specify callbacks that execute before the worker attempts to fetch a job from a queue. For example, you might register a closure to rollback any transactions that were left open by a previously failed job:
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Queue;
Queue::looping(function () {
while (DB::transactionLevel() > 0) {
DB::rollBack();
}
});