MaxAttemptsExceededExceptionと10時間くらい戦って気付いたことを書きます。
環境
- PHP 7.4.3
- Laravel Framework 6.14.0
この例外 is 何
has been attempted too many times or run too long. The job may have previously timed out.
ジョブのタイムアウト時、もしくはジョブの試行回数が設定値を超えた場合に発生する。
この例外が発生する条件
この例外に関連する登場人物(設定値)は以下の3つ。
- timeout
- retry_after
- tries
このいずれかの設定値が間違っていると、意図せずこの例外が吐かれる可能性がある。
設定値について
ジョブ自体に設定することもできるし、ジョブ実行時にオプションで設定することもできる。
どちらも設定した場合は、ジョブ自体に設定したほうが優先される。
retry_afterに関してはconfig/queue.phpでしか設定できないっぽい。
ジョブ自体に設定する場合
...
class ExampleJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, Notifiable;
public $timeout = 1; // タイムアウト秒数
public $tries = 1; // 試行回数
...
}
ジョブ実行時に設定する場合
$ php artisan queue:work --timeout=1 --tries=1
retry_afterの設定
バックエンドサービスにdatabaseを使う場合の例です。
'connections' => [
...
'database' => [
'driver' => 'database',
'table' => 'jobs',
'queue' => 'default',
'retry_after' => 1,
],
...
],
気付いたこと
timeoutを設定する場合、retry_afterも設定する必要がある
キュー 6.x Laravel
https://readouble.com/laravel/6.x/ja/queues.html--timeout値は、最低でも数秒retry_after設定値よりも短くしてください。これにより、与えられたジョブを処理するワーカが、ジョブのリトライ前に確実にkillされます。--timeoutオプションをretry_after設定値よりも長くすると、ジョブが2度実行されるでしょう。
timeoutだけを設定して安心してはいけません。それは罠です。
retry_afterをtimeoutより長く設定しないと、ジョブが意図せず再試行され、MaxAttemptsExceededExceptionに繋がる可能性があります。
tries=0にするとfailedメソッドが動かなくなる
tries=0でジョブを実行すると、例外発生時にfailedメソッドが動作しません。
triesの設定値は1以上を推奨します。
余談
キューを使う上で知っておきたいこと も書いてみました。
こちらも参考になるかもしれません。