Laravelキュー最小構成入門【Redis未使用】


Laravelでキューを使ってみたかったんだけど、世のドキュメントが公式も非公式もやたら小難しく、分かりづらかったので時間がかかった。

Redisは使わずに、`database`ドライバの最小構成でキューを試していく。

<details>
<summary>キュー[queue]・キューワーカー・ジョブとは（概要[CHATGPT])</summary>


Laravelのキュー(queue)、キューワーカー(worker)、およびジョブ(job)について簡潔に説明します。

キュー(queue):

キューはタスクやジョブを非同期に処理する仕組みです。
特定の処理を直ちに実行せず、後で実行するためのキューにタスクを入れることができます。
ジョブ(job):

ジョブはキューに入れられる実際の処理単位です。
通常、時間のかかる処理や非同期に実行されるべき処理をジョブとして定義します。
キューワーカー(worker):

キューワーカーは、キューに入れられたジョブを非同期に実行するプロセスです。
キューワーカーはジョブを取り出し、実行し、次々にキュー内のジョブを処理します。
簡単な例を挙げると、以下のような流れです：

Laravelアプリケーション内で、時間のかかる処理をキューに追加したい場合、その処理をジョブとして定義します。
ジョブはキューにプッシュされ、即座にレスポンスを返すことができます。
キューワーカーがバックグラウンドで動作していると、そのキューからジョブを取り出し、非同期に処理します。
この仕組みにより、ユーザーは待たずにアプリケーションを使用でき、時間のかかる処理はバックグラウンドで実行されます。
</details>

## 本筋
サクッとLaravel Queueデビューしていく

### 準備編
- 前提
    - 一般的なLaravelプロジェクトが作成済。
    - （筆者の環境はLaravel 9）

`database`ドライバでキューを管理するためには、プロジェクトに`jobs`データベーステーブルが必要となる。

```bash:jobsテーブルの作成
php artisan queue:table
php artisan migrate
```

次に、`config/queue.php`ファイル内部で参照されている`.env`の`QUEUE_CONNECTION`項目を`sync`から`database`に変更しておく。

```.env:.env
//...
#QUEUE_CONNECTION=sync
QUEUE_CONNECTION=database

//...
```

続いてジョブクラスを作成していく。
ジョブクラスには実際の重たい処理を記述する。

※`Artisan::queue()`を使えば必須ではないが、普通に不便で分かりづらいので作成していく。

```bash:Jobクラス作成
php artisan make:job TestJob
```

コマンドを実行すると、プロジェクトに`App\Jobs`配下に`TestJob`クラスが作成される。

```php:App\Jobs\TestJob.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;

class TestJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    /**
     * ジョブを試行する回数。
     *
     * @var int
     */
    public $tries = 3;

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        // The Heavy Process

    }

    public function failed($exception)
    {
        //Log::channel('laravel')->error($exception);
    }
}

```

これで処理の記述は完了したが、動作させるためには、実際のジョブを実行する為のキューワーカーを起動させる必要がある。


## キューワーカー起動

```bash:キューワーカー実行
#20分以内に1つのジョブが終わらない場合、エラーとなる。
php artisan queue:listen --timeout=1200
```

キューワーカーの注意点として、プロジェクトにソースコードの変更があった場合にもキューワーカーは変更を感知しない。
ソースコードを反映させたい場合は次のコマンドで、キューワーカーの再起動を行う必要がある。

```bash:キューワーカー再起動
php artisan queue:restart
```

## 実際にジョブを実行

別プロセスでキューワーカが動いてくれているので、メインのプロセスからジョブをキューへ入れてみる。

```php:ExampleClass.php
use App\Jobs\TestJob;

//...

// ジョブをキューに割り当てる
TestJob::dispatch()
  // 10秒遅れて起動
  ->delay(now()->addSeconds(10));
  
```

dispatchは仕事を割り当てるとかの意味らしい。

### 解説

dispatchすると、ジョブが`jobs`テーブルに挿入される。
キューワーカーは、折を見て（自分が暇なときに）`jobs`テーブルから仕事を見つけてきて、実行する。

つまり、キューワーカーはメインプロセス（API応答や、リソース描画）とは完全に別なチャンネルで動いているので、非同期なアクションを実現できる。

ジョブが成功すると、`jobs`テーブルからレコードが削除される。
ジョブが失敗した場合は、`failed_jobs`テーブルに記録される。

※failed_jobsテーブルはある程度のverのLaravelからはマイグレーションが初期搭載されている。

## おまけ
`public function retryUntil()`の使い道がいまひとつわからなかった。
コマンドでキューワーカーを動かす際に `--timeout=1200`と指定しないと反映されないように見える。


## 参考
https://qiita.com/_hiro_dev/items/eef6778179e692507c84

https://qiita.com/segawa/items/59e3d12015a2bf126aab

https://www.konosumi.net/entry/2021/12/26/125411

https://readouble.com/laravel/9.x/ja/queues.html