このエクステンションを使うためには、以下のように構成しなければなりません。
return [
'bootstrap' => [
'queue', // queue コンポーネントが自身のコンソール・コマンドを登録します
],
'components' => [
'queue' => [
'class' => \yii\queue\<driver>\Queue::class,
'as log' => \yii\queue\LogBehavior::class,
// 他のドライバ・オプション
],
],
];
利用可能なドライバとそのドキュメントは 目次 に記載されています。
キューに送られるタスクはそれぞれ独立したクラスとして定義されなければなりません。 例えば、ファイルをダウンロードして保存すう必要がある場合、そのクラスは以下のようなものになります。
class DownloadJob extends BaseObject implements \yii\queue\JobInterface
{
public $url;
public $file;
public function execute($queue)
{
file_put_contents($this->file, file_get_contents($this->url));
}
}
以下のようにして、キューにタスクを送ります。
Yii::$app->queue->push(new DownloadJob([
'url' => 'http://example.com/image.jpg',
'file' => '/tmp/image.jpg',
]));
5 分後に走るべきジョブをキューにプッシュするには、
Yii::$app->queue->delay(5 * 60)->push(new DownloadJob([
'url' => 'http://example.com/image.jpg',
'file' => '/tmp/image.jpg',
]));
重要: 全てのドライバが遅延実行をサポートしている訳ではありません。
タスクがどのように実行されるかは、正確には、使用されるドライバに依存します。 ほとんどのドライバでは、コンポーネントがアプリケーションに登録したコンソール・コマンドを使って実行されます。 詳細は、対応するドライバのドキュメントを参照して下さい。
queue コンポーネントは、キューにプッシュされたジョブの状態を追跡することが出来ます。
// ジョブをキューにプッシュして、メッセージ ID を取得する
$id = Yii::$app->queue->push(new SomeJob());
// ジョブが実行待ちであるかチェックする
Yii::$app->queue->isWaiting($id);
// ワーカがキューからジョブを受け取って実行しているかチェックする
Yii::$app->queue->isReserved($id);
// ワーカがジョブを完了したかチェックする
Yii::$app->queue->isDone($id);
重要: RabbitMQ ドライバはジョブの状態追跡をサポートしていません。
キューにはどのようなデータでも渡すことが出来ます。
Yii::$app->queue->push([
'function' => 'download',
'url' => 'http://example.com/image.jpg',
'file' => '/tmp/image.jpg',
]);
このことは、キューが特別なサード・パーティのワーカを使って処理される場合に有用となります。
ワーカが PHP で実装されているのではない場合、データをシリアライズする方法を変更しなければなりません。 例えば、JSON にシリアライズする場合は、
return [
'components' => [
'queue' => [
'class' => \yii\queue\<driver>\Queue::class,
'strictJobType' => false,
'serializer' => \yii\queue\serializers\JsonSerializer::class,
],
],
];
キューは以下のイベントをトリガします。
イベント名 | イベント・クラス | トリガされるタイミング |
---|---|---|
Queue::EVENT_BEFORE_PUSH | PushEvent | Queue::push() メソッドを使ってジョブをキューに追加する前 |
Queue::EVENT_AFTER_PUSH | PushEvent | Queue::push() メソッドを使ってジョブをキューに追加した後 |
Queue::EVENT_BEFORE_EXEC | ExecEvent | ジョブを実行する前 |
Queue::EVENT_AFTER_EXEC | ExecEvent | ジョブが完了した後 |
Queue::EVENT_AFTER_ERROR | ErrorEvent | ジョブ実行中にキャッチされない例外が発生したとき |
cli\Queue:EVENT_WORKER_START | WorkerEvent | ワーカが開始されたとき |
cli\Queue:EVENT_WORKER_LOOP | WorkerEvent | キューに対するリクエストを繰り返すたびに |
cli\Queue:EVENT_WORKER_STOP | WorkerEvent | ワーカが停止されたとき |
これらのイベントの全てに対してあなた独自のハンドラをアタッチすることが簡単にできます。 例えば、ジョブが特殊な例外で失敗した場合に、時間をおいて再実行させてみましょう。
Yii::$app->queue->on(Queue::EVENT_AFTER_ERROR, function ($event) {
if ($event->error instanceof TemporaryUnprocessableJobException) {
$queue = $event->sender;
$queue->delay(7200)->push($event->job);
}
});
queue コンポーネントは Yii の内蔵ロガー
を使ってキューのイベントを記録する LogBehavior
を提供しています。
これを有効にするためには、queue コンポーネントを以下のように構成するだけです。
return [
'components' => [
'queue' => [
'class' => \yii\queue\redis\Queue::class,
'as log' => \yii\queue\LogBehavior::class
],
],
];
構成例:
return [
'bootstrap' => [
'queue1', // 第一のコンポーネントがそれ自身のコンソール・コマンドを登録
'queue2', // 第二のコンポーネントがそれ自身のコンソール・コマンドを登録
],
'components' => [
'queue1' => [
'class' => \yii\queue\redis\Queue::class,
],
'queue2' => [
'class' => \yii\queue\db\Queue::class,
'strictJobType' => false,
'serializer' => \yii\queue\serializers\JsonSerializer::class,
],
],
];
使用例:
// 標準のワーカで処理されるジョブをキューに送る
Yii::$app->queue1->push(new DownloadJob([
'url' => 'http://example.com/image.jpg',
'file' => '/tmp/image.jpg',
]));
// サード・パーティのワーカで処理されるタスクを別のキューに送る
Yii::$app->queue2->push([
'function' => 'download',
'url' => 'http://example.com/image.jpg',
'file' => '/tmp/image.jpg',
]);
キューを使用する場合、キューに置かれたタスクは独立したプロセスによって取得される、ということを覚えておくことが重要です。 タスクを実行するときに外部的な依存は避けなければなりません。 なぜなら、ワーカがジョブを実行する環境においてその依存を利用できるとは限らないからです。
タスクを処理するために必要なデータは、ジョブ・オブジェクトのプロパティに設定して、ジョブと一緒にキューに送らなければなりません。
ActiveRecord
を扱う必要がある場合は、オブジェクトそのものではなく、ID を送ります。
そして、処理するときに DB から読み出します。
例えば、
Yii::$app->queue->push(new SomeJob([
'userId' => Yii::$app->user->id,
'bookId' => $book->id,
'someUrl' => Url::to(['controller/action']),
]));
タスク・クラス:
class SomeJob extends BaseObject implements \yii\queue\JobInterface
{
public $userId;
public $bookId;
public $someUrl;
public function execute($queue)
{
$user = User::findOne($this->userId);
$book = Book::findOne($this->bookId);
//...
}
}