shinke1987.net
雑多な備忘録等のはず。
他のカテゴリ・タブ
目次
PR

Laravelでのキューの動作確認

2025-04-20 2025-04-20

前提

Laravelのバージョン:11.20.0

キューの内容はDBに保存する設定で、必要なテーブルもマイグレートされていることを前提とする。

(デフォルトの状態でマイグレートすればそうなっているはず)

全体的な注意点としてジョブや他のファイルを変更した後、
キューワーカを再起動することを忘れずに。

準備

ジョブの作成

次のコマンドでキューに入れるジョブを作成する。

php artisan make:job TestJob

作成されたTestJobクラスのhandleメソッドを次のように編集する。

public function handle(): void

{

    Log::info('TestJob');

}

動作確認用コントローラの作成

次のコマンドで今回の動作確認用のコントローラを作成する。

php artisan make:controller Test

作成されたTestコントローラに次のメソッドを追記する。

public function TestJob()

{

    TestJob::dispatch();

    return view('welcome');

}

ルーティングの設定

routes/web.phpにて、デフォルトのルートをコメントアウトし、(削除しても良い)
次のように編集する。

//Route::get('/', function () {

//    return view('welcome');

//});

Route::get('/', [\App\Http\Controllers\Test::class, 'TestJob']);

シンプルな動作確認

目的

ジョブをキューに入れて、

DBがどうなっているのかを見て、

キューに入れたジョブがどう実行されるのか確認する。

ジョブをキューへ入れる。

http://localhost へ1回アクセスして、次のSQLを実行する。

SELECT * FROM jobs;

次のような結果が得られるはず。

idqueuepeyloadattemptsreserved_atavailable_atcreated_at
数字default{“uuid”:”bb78e2f3-13e5-4535-af52-645f2b65b4c0″,”displayName”:”App\\Jobs\\TestJob”,”job”:”Illuminate\\Queue\\CallQueuedHandler@call”,”maxTries”:null,”maxExceptions”:null,”failOnTimeout”:false,”backoff”:null,”timeout”:null,”retryUntil”:null,”data”:{“commandName”:”App\\Jobs\\TestJob”,”command”:”O:16:\”App\\Jobs\\TestJob\”:0:{}”}}0null17450732561745073256

available_atとcreated_atの値はUNIXタイムスタンプなので、変換して見てもらいたいが、available_atとcreated_atの値が同一であることを見れば何となく用途がわかるはず。

このjobsテーブルへ上記のようなデータがあれば、作成されたジョブがキューに入ったと確認できる。

キューに入っているジョブを実行する

キューワーカを起動するために次のコマンドを実行すれば良い。

php artisan queue:work

次のように画面にジョブが実行された旨が表示される。

INFO Processing jobs from the [default] queue. 

2025-04-19 15:17:05 App\Jobs\TestJob ........................................................... RUNNING

2025-04-19 15:17:05 App\Jobs\TestJob ...................................................... 18.12ms DONE

また、ログファイル(storage/logs/laravel.log)を見ると次のようなログが記録されている。

[2025-04-19 15:17:05] local.INFO: TestJob

jobsテーブルを先ほどのSQLで確認すると、データは無くなっている。

キューワーカが実行中にジョブをキューに入れる

上記のartisanコマンドが実行され続けていることを確認して、

再度http://localhostへアクセスし、

ジョブをキューへ格納すると即実行されることを確認すれば良い。

レート制限の動作確認

試した中では2パターンの使い方ができそう。

  1. 1. 指定した時間を経過するたびにキュー内のジョブを1個実行する。ただし、キュー内のジョブの数を把握する必要がある。
  2. 2. 指定した時間を経過しないとキューへジョブを追加できないようにする。キューへ追加されたジョブは即実行される。

1番目の指定した時間を経過するたびにキュー内のジョブを1個実行する場合の例

前提:上記のシンプルな動作確認の内容を流用する。

TestJob.php の内容を次のように編集する。

<?php

namespace App\Jobs;

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Queue\Middleware\RateLimited;
use Illuminate\Support\Facades\Log;

class TestJob implements ShouldQueue
{
    use Queueable;

    public $tries = 0;
    /**
     * Create a new job instance.
     */
    public function __construct()
    {
        //
    }

    /**
     * Execute the job.
     */
    public function handle(): void
    {
        Log::info('TestJob' . mt_rand(10, 20));
    }

    public function middleware(): array
    {
        return [(new RateLimited('TestJob1min'))];
    }
}

app/Providers/AppServiceProvider.php の内容を次のように編集する。

<?php

namespace App\Providers;

use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        //
    }

    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        RateLimiter::for('TestJob1min', function() {
            // 15秒に1回しか許可しない。
            return Limit::perSecond(1, 15);
        });
    }
}

上記内容でhttp://localhostへ3回アクセスすると、

各ジョブの処理が15 + α秒で実行されていることが確認できる。

2番目の指定した時間を経過しないとキューへジョブを追加できないようにする場合の例

前提:上記のシンプルな動作確認の内容を流用する。

前提2:上記のAppServiceProvider.php の内容を流用する。

TestJob.php の内容を次のように編集する。

<?php

namespace App\Jobs;

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Queue\Middleware\RateLimited;
use Illuminate\Support\Facades\Log;

class TestJob implements ShouldQueue
{
    use Queueable;

    /**
     * Create a new job instance.
     */
    public function __construct()
    {
        //
    }

    /**
     * Execute the job.
     */
    public function handle(): void
    {
        Log::info('TestJob' . mt_rand(10, 20));
    }

    public function middleware(): array
    {
        return [(new RateLimited('TestJob1min'))->dontRelease()];
    }
}

上記内容でhttp://localhostへ15秒以内に3回アクセスすると、

ジョブは1個しか実行されず、キュー内(jobsテーブル)のジョブは0個となっていることが確認できる。

その15秒後に再度アクセスすると、ジョブはまた1個実行されることが確認できる。

一意なジョブの動作確認

キュー内で$uniqueIdが指定されたジョブがある場合、同一の$uniqueIdを持つジョブを新たに追加できなくなることを確認する。

(キュー内で$uniqueIdが指定されたジョブは、$uniqueIdに基づいて一意のものとなる。)

レート制限の動作確認の

1番目の指定した時間を経過するたびにキュー内のジョブを1個実行する、を流用して確認する。

TestコントローラのTestJobメソッドの内容を次のように編集する。

public function TestJob(Request $request)
    {
        TestJob::dispatch(100);
        return view('welcome');
    }

TestJob.php の内容を次のように編集する。

ShouldBeUniqueのインターフェイスを追加している点に注意。

<?php

namespace App\Jobs;

use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Queue\Middleware\RateLimited;
use Illuminate\Support\Facades\Log;

class TestJob implements ShouldQueue, ShouldBeUnique
{
    use Queueable;

    public $tries = 0;
    public $uniqueId;

    /**
     * Create a new job instance.
     */
    public function __construct(int $intValue)
    {
        Log::info("TestJob Constructor \$intValue = {$intValue}");
        $this->uniqueId = $intValue;
    }

    /**
     * Execute the job.
     */
    public function handle(): void
    {
        Log::info('TestJob' . mt_rand(10, 20));
    }

    public function middleware(): array
    {
        return [(new RateLimited('TestJob1min'))];
    }
}

上記内容でhttp://localhostへ15秒以内に3回以上アクセスしても、

ジョブは2回しか実行されないことが確認できる。

1回目はキューへ入れた瞬間実行され、

2回目は一意であるためキューへ入れることができ、

3回目以降は$uniqueIdが同一であるジョブが、キュー内に存在するためキューへ入れることができない。

Tips

キュー内のジョブ数を取得

DBから直接取得しても良いかもしれない。

use Illuminate\Support\Facades\Queue;

Queue::size('default');

ジョブに設定したuniqueIdを取得

DBから引っ張るやり方になる。

キューに1個のジョブがある状態で実行する例。

$dbResult = DB::table('jobs')->select('payload')->get();

$uniqueId = unserialize(json_decode($dbResult->all()[0]->payload)->data->command)->uniqueId;
同一カテゴリの記事