[Laravel] キューのsleepとtimeoutの関係

Laravelのキューを実際に使ってみた際にちょっと変な挙動だと思ったメモ。

sleep

キューを実行するコマンドのオプションにsleepというものがある。
コマンドのヘルプの説明は以下。

1
--sleep[=SLEEP]      Number of seconds to sleep when no job is available [default: "3"]

ジョブがない場合に次のジョブを取得するまでにスリープする秒数の設定、とのこと。
例えばこれをゼロにすると、常にジョブを取得するためのポーリングが実行され続けるため、ジョブの保存先をキューイングサービスなどにしている場合に、ものすごい数のキュー取得リクエストが飛んでしまう。
なのでsleepを設定してやれば(ジョブがなくなった時に)、ポーリング間隔を空ける事が出来るので負荷が減ったりする。

timeout

処理のtimeoutオプション。

1
--timeout[=TIMEOUT]  The number of seconds a child process can run [default: "60"]

処理に指定した時間以上の時間がかかった場合はタイムアウトとする設定。デフォルトは60秒。

sleepとtimeoutの関係

sleepの時間を長く設定すると、タイムアウトエラーが発生してしまう。
例えば以下。

1
php artisan queue:listen --sleep=120 --timeout=60

というのも、次のキュー取得を実行するまでのスリープ時間もタイムアウトの対象の時間に含まれてしまう、よう。
なので必ずsleep時間よりもtimeoutの時間を多く設定してやらないといけない。
上記の場合だとsleepを120秒にしてるので、timeoutを(少なくとも)120秒より大きく設定しないといけない。

1
php artisan queue:listen --sleep=120 --timeout=125

これだと無事、動作する。
(処理内容に5秒以上かかると合計が125秒を越えてしまうのでタイムアウトになるが)

疑問

単にポーリングの待ち時間のはずなのに実行時間のタイムアウトの対象に含まれるのはおかしいのでは?という疑問はやはり出ていたようで、Githubのissueでやりとりがされていた。

queue:listen's sleep duration contributing towards timeout · Issue #6206 · laravel/framework

内容を読んでいくと、そもそものプロセスの処理に組み込まれてしまっているため、根本的な修正は難しく、timeoutの時間をsleep時間を足して設定してやる、とかしか無理じゃない?みたいなやり取りになっている。

そしてその後、5.1の時にtimeout時間をsleep時間よりも短く設定出来ないようにする制限が組み込まれたようだが、巨大な処理を行う場合にtimeoutをなしにするためにゼロ秒にセットしたいのに出来ない、という意見が出て結局削除されている。

結果、制約も入らず対処もされていないようなので、現状は前述のように、timeout時間をsleep時間より必ず大きく設定してやらないといけない、ということになっているよう。

余談

キューのサンプルを作っている時に事象に遭遇したのだけど、そのキューのサンプルはGitHubにあげてる。
HerokuButtonで起動できるようにしたりしてみたので、よかったらお試しあれ。

https://github.com/k-usk/laravel-queue-sample

   このエントリーをはてなブックマークに追加