ブログ
これまでに経験してきたプロジェクトで気になる技術の情報を紹介していきます。
Laravel Queues
Queues
時間のかかるタスクをバックグラウンドで実行する機能
実行したい処理(ジョブ)をリスト(キュー)に入れて置き、後で実行(ワーカ)するもの
コネクション
コネクションは「sync」、「database」、「beanstalkd」、「sqs」、「redis」などが使え、 config/queue.php
の connections
に設定
「sync」はデフォルトで .env
に設定されており同期処理される
databaseを使って実装
databaseコネクションの選択
.env
の QUEUE_CONNECTION
を「sync」から「database」に変更
QUEUE_CONNECTION=database
テーブルの準備
artisanでキューが保存されるテーブルのマイグレーションファイルを作成
php artisan queue:table
2021_xx_xx_xxxxxx_create_jobs_table.php
が作成される
migrateする
php artisan migrate
以下の2つのテーブルが作成されていることを確認
- jobs
- failed_jobs
ジョブの作成
php artisan make:job SampleJob
app\Jobs\SampleJob.php
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
// 追加
use Illuminate\Support\Facades\Log;
use App\Models\User;
class SampleJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
// パラメータを使う場合は宣言
public $user;
/**
* Create a new job instance.
*
* @return void
*/
// ユーザを使うのでコンストラクタの引数に「User $user」を追加
public function __construct(User $user)
{
$this->user = $user; // 追加
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
$date = now()->format('Y-n-j H:i:s');
// ログファイルにユーザと時間を表示
Log::info("{$this->user->id}: {$this->user->name} [{$date}]");
}
}
テストコントローラを作成
ジョブを登録するには dispatch
メソッドを使用する
php artisan make:controller TestController
app\Http\Controllers\TestController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Jobs\SampleJob;
use App\Models\User;
class TestController extends Controller
{
public function index()
{
// get user
$user = User::find(1);
// set job
// dispatchでキューに登録
SampleJob::dispatch($user);
return 'aet job!';
}
}
テストルートを作成
Route::get('/test', [TestController::class, 'index']);
実行
http://localhost/test
にブラウザでアクセスする
これでjobsテーブルにジョブが追加される
id | queue | payload | attempts | reserved_at | available_at | created_at |
---|---|---|---|---|---|---|
1 | default | {"uuid":"62021aef-afa7-4842-9ad7-7fd... | 0 | nill | 1630053240 | 1630053240 |
キューを実行
artisanでキューを実行する
php artisan queue:work
# output
[2021-08-27 08:40:30][1] Processing: App\Jobs\SampleJob
[2021-08-27 08:40:30][1] Processed: App\Jobs\SampleJob
storage\logs\laravel.log
[2021-08-27 08:40:30] local.INFO: 1: user1 [2021-8-27 08:40:30]
redisに変更
predisモジュールを追加
モジュールを追加
composer require predis/predis
redisコネクションの選択
.env
QUEUE_CONNECTION=redis
redisで実行
php artisan queue:work
プロパティ
app\Jobs\SampleJob.php
/**
* ジョブの一意のロックが解放されるまでの秒数
*
* @var int
*/
public $uniqueFor = 3600;
/**
* タイムアウトになる前にジョブを実行できる秒数
*
* @var int
*/
public $timeout = 120;
/**
* ジョブを試行する回数。
*
* @var int
*/
public $tries = 5;
/**
* 失敗する前に許可する未処理の例外の最大数
*
* @var int
*/
public $maxExceptions = 3;
/**
* ジョブがタイムアウトで失敗したとマークするかを指定
*
* @var bool
*/
public $failOnTimeout = true;
メソッド
キューの待機時間
ジョブがキューに入ってから設定時間待機してから実行させる
// 1分後を取得
$delay = now()->addMinutes(1);
// キューにディスパッチ、1分後に実行
SampleJob::dispatch($user)->delay($delay);
別のConnectionを利用
// コネクションredisを選択
SampleJob::dispatch($user)->onConnection('redis');
別のキューを利用
// コネクションredisを選択
SampleJob::dispatch($user)->onQueue('myQueue');
# defaultだけ実行
php artisan queue:work
# myQueueだけ実行
php artisan queue:work --queue=myQueue
# 複数実行、順に優先度になる
php artisan queue:work --queue=default,myQueue
コマンド
実行コマンド
queue:work
: コードの変更があれば一度停止して、再度起動する必要がある、負荷小、本番用queue:listen
: 一度起動をすればコードの修正を行なっても再起動する必要がない、負荷大、開発用queue:work --delay [second]
: ジョブが失敗すると指定秒後に再実行するよう--dilay
オプションを付けて実行queue:work --tries [times]
: リトライする回数を--tries
で指定して実行、1以上queue:work --timeout [second]
: タイムアウト時間(秒)を--timeout
で指定して実行、config\queue.php
で指定するretry_after
より小さくなくてはいけないqueue:work --queue=[queue]
: キューを指定して実行queue:work [connection]
: コネクションを指定して実行queue:work [connection] --queue=[queue]
: コネクションとキューを指定して実行queue:restart
: 再起動
実行終了コマンド
queue:work --once
: キューから1つのジョブのみ実行して終了queue:work --max-jobs=[times]
: 処理するジョブの数を指定して実行して終了queue:work --stop-when-empty
: すべてのジョブを処理してから終了queue:work --max-time=[second]
: 指定する秒数の間ジョブを処理してから終了
キューからのジョブクリア
queue:clear
: キューをすべてクリアqueue:clear [connection] --queue=[queue]
: コネクションとキューを指定してクリア
失敗コマンド
queue:failed [uuid]
: コマンドを実行すると失敗したジョブの情報が登録されていることが確認できるqueue:retry [uuid]
: 失敗したジョブのuuidを指定して再実行queue:retry [id]
: 失敗したジョブのidを指定して再実行queue:retry [id id id]
: 失敗したジョブのidを指定して再実行queue:retry --range=[id-id]
: 失敗したジョブのidをレンジで指定して再実行queue:forget [uuid]
: 失敗したジョブのuuidを指定して削除queue:forget [id]
: 失敗したジョブのidを指定して削除queue:flush
: 失敗したジョブの一括削除queue:retry --queue=[queue]
: 失敗したジョブのキューを指定して再実行queue:retry all
: 失敗したジョブをすべて再実行
テーブルコマンド
queue:table
: jobsテーブル作成queue:failed-table
: failed_jobsテーブル作成
config
config/queue.php
の connections
に設定されているretry_after
は
キューが実行されてからリトライするまでの時間(秒)
redisのみ対応
1つのジョブを実行してから次のジョブまでの待機時間
イメージとしは以下のような感じ
while(true){
$job = getJob();
// job process
sleep(5);
}
ジョブ失敗処理
failed
メソッドを作成して
/**
* ジョブの実行
*/
public function handle(AudioProcessor $processor)
{
// Process uploaded podcast...
}
/**
* ジョブの失敗を処理
*
* @param \Throwable $exception
* @return void
*/
public function failed(Throwable $exception)
{
// ロールバックの処理を追加したり、
// ユーザへ処理の失敗を通知したりできる
}
コメントはありません。