December 29, 2021 • ☕️ 4 min read
【 環境 】
Laravel のバージョン: 8.16.1
PHP のバージョン: 7.4.7
MySQL のバージョン: 5.7
前回、こんなのを書きました。
【Laravel】ジョブがタイムアウトした場合、エラー扱いにして特定の処理を実行する事はできない?
<概要>
ジョブが失敗した時に自動で実行するメソッド( failed メソッド)が用意されていて、そこに失敗した時の処理を記述する事ができる。しかし、タイムアウト時には failed メソッドが実行されない。
タイムアウト発生時に何かしらの処理を実行させる事はできないのでは?
色々試してみた結果、タイムアウト発生時に failed メソッドを実行する事が出来ました。
実は、タイムアウト時間を自由に制御するには pcntl というプロセス制御機構が必要となり、これを有効化する必要がある。
詳細および設定方法については、こちらを。
Laravel : ジョブのタイムアウトを設定には、pcntl(PHPの拡張項目)を有効化する必要がある
PHP・Docker:Docker コンテナ起動の PHP にて、pcntl を有効にする方法
前回、キューの待ち受けコマンドに「queue:listen」を使っていたのですが、「queue:work」で動かしてみました。
具体的には、以下のコマンドを使用しています。
php artisan queue:work --tries=3 --timeout=10
ジョブのタイムアウト時間を 10秒に設定しています。
ジョブ実行時に、70秒のウェイトがかかるようにしています。
上記コマンドにて、タイムアウト時間が 10秒としているので、必ずタイムアウトが発生するようになります。
class MyJob12 implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* The number of times the job may be attempted.
*
* @var int
*/
public $tries = 3;
/**
* Indicate if the job should be marked as failed on timeout.
*
* @var bool
*/
public $failOnTimeout = true;
/**
* Create a new job instance.
*
* @return void
*/
public function handle()
{
\Log::info(__METHOD__);
sleep(70); // 70秒ウェイト
\Log::info('70 second passed');
}
/**
* ジョブの失敗を処理
*
* @param \Throwable $exception
* @return void
*/
public function failed(Throwable $exception)
{
// ユーザーへ失敗を通知するなど…
echo "Send user notification of failure, etc...";
\Log::info("Send user notification of failure, etc...");
}
}
[2021-12-30 03:24:41] local.INFO: App\Jobs\MyJob12::handle
[2021-12-30 03:24:51] local.INFO: Send user notification of failure, etc...
こんな感じで、タイムアウト時に failed メソッドが実行されました。
「queue:listen」の場合、1度コマンドを実行すると後はずっと動いてくれるので、cron などで定期的にジョブ実行する仕組みが不要となる。
しかし、「queue:work」は1回しか実行してくれないので、本番環境やステージング環境で動かす場合、定時実行の仕組みを用意する必要がある。
ちょっと面倒だけど、タイムアウト時に特定のフラグを解除しないと後続バッチに影響が出る、といった場合はその方法がよさそう。
ちなみに、何故 listen と work の違いで、このような挙動の差が生まれているのかまではよく分かってません。
何となく、Laravel のバグっぽい気がします。