9️⃣

Laravel Queues

2024/04/24に公開
  • Laravel Queuesからの抜粋
  • connection は "database" のみ。Redis や Amazon SQS はよく解らない

最も単純な構成

1. Job を作成

  • artisan コマンドでクラスを作成
    php artisan make:job ProcessPodcast
    
  • クラスに処理を記述
    App/Jobs/ProcessPodcast.php
    public function __construct(
        public Podcast $podcast,
    ) {}
    
    public function handle(): void
    {
        logger("Job を実行 {$this->podcast->name}");
    }
    

2. Job を Queue に入れる

  • Controller などで dispatch する
    App/Http/Controllers/Controller/PodcastController.php
    public function store(Request $request): RedirectResponse
    {
        $podcast = Podcast::create(/* ... */);
    
        ProcessPodcast::dispatch($podcast);
    
        return redirect('/podcasts');
    }
    
  • jobs にレコードが登録される

3. Job を実行する

  • artisan コマンドで実行する
    php artisan queue:work
    
  • Jobが成功した場合、jobs からレコードは削除される
  • Jobが失敗した場合、failed_jobs に記録される

複数の Queue を扱う

  • Dispatching to a Particular Queue

  • queue の名前を指定しない場合、"default" が適用される

  • Job もしくは dispatch 時に queue を指定できる

    App/Jobs/ProcessPodcast.php
    public function __construct(
        public Podcast $podcast,
    ) {
        $this->onQueue('processingPodcast');
    }
    
    App/Http/Controllers/Controller/PodcastController.php
    public function store(Request $request): RedirectResponse
    {
        $podcast = Podcast::create(/* ... */);
    
        ProcessPodcast::dispatch($podcast)->onQueue('processingPodcast');
    
        return redirect('/podcasts');
    }
    

  • Job を実行する際には Queue 名を指定する(指定した順に優先度高)

    php artisan queue:work --queue=processingPodcast,default
    

複数種類のJobを連続して実行する

  • Job Chaining
  • dispatch 時に Chain を構成する
    App/Http/Controllers/Controller/PodcastController.php
    use App\Jobs\Job1;
    use App\Jobs\Job2;
    use Illuminate\Support\Facade\Bus;
    public function store(Request $request): RedirectResponse
    {
        $podcast = Podcast::create(/* ... */);
    
        Bus::chain([
            new Job1($podcast),
            new Job2(),
        ])->onQueue('processingPodcast')->dispatch();
    
        ProcessPodcast::dispatch($podcast)->onQueue('processingPodcast');
    
        return redirect('/podcasts');
    }
    
  • 先行する Job が失敗した場合、後続する Job は実行されない
  • 実行される Queue について
    • onQueue で指定した Queue
    • 各 Job クラスで指定した Queue ← こちらが優先

タイムアウト

  • Timeout
  • デフォルトのタイムアウトは 60 秒
  • Job の属性もしくは artisan コマンドで指定する
    App/Jobs/ProcessPodcast.php
    public $timeout = 120;
    
    php artisan queue:work --timeout=30
    

Commitの待機

  • Specifying Commit Dispatch Behavior Inline
  • dispatch するためにトランザクションの終了を待つか待たないか指定する
    • 親を含むすべてのトランザクションが対象となる
  • config もしくは、dispatch 時に指定することができる
    config/queue.php
    `database` => [
        'after_commit' => true,
    ]
    
    App/Http/Controllers/Controller/PodcastController.php
    public function store(Request $request): RedirectResponse
    {
        $podcast = Podcast::create(/* ... */);
    
        ProcessPodcast::dispatch($podcast)->afterCommit();
    
        return redirect('/podcasts');
    }
    
  • トランザクションが rollback された場合、トランザクション中に dispatch された Job は破棄される
    App/Http/Controllers/Controller/PodcastController.php
    public function store(Request $request): RedirectResponse
    {
        DB::transaction(function () {
            $podcast = Podcast::create(/* ... */);
    
            ProcessPodcast::dispatch($podcast);
    
            throw new \Exception("test");
        });
        return redirect('/podcasts');
    }
    

その他

  • Queued Relationships
    • Job に引き渡した Eloquent モデルのリレーションの扱いについて
  • Unique Jobs
    • 同じ Job を同時に Queue に追加したくない
    • 実行間隔の指定、同一判定の実装を追加する
  • Job Middleware
    • Routing の Middleware と同じ仕組み
    • 各 Job に共通の処理(レート制限など)を差し込む用途
    • レート制限は標準の実装がある

Discussion