【PHP】タイムアウト(set_time_limit)を設定しているのにタイムアウトされない現象を調べてみた

2021年08月18日2021年08月18日
PHP

APIを実行してからAPIレスポンスが返却されるまで時間がかかることが何度かあります。

通常であれば1〜3秒で返してくれるのですが、遅い時は60秒とかかかることがあります。

そこで「set_time_limit()」を使ってタイムアウトの値を変更しようと思ったらどつぼにはまりました。

max_execution_timeの設定を無制限に変更したい

max_execution_timeの値は、set_time_limit()関数使うことでPHPのプログラム側で書き換えることができます。

やりたかったことは、「API接続中にタイムアウトを回避したいので、タイムアウトを無制限に設定したい」というものです。

ローカル環境でとりあえず試してみる

とりあえず、ローカル環境でテストです。

max_execution_timeはデフォルトだと30秒が設定されています。

つまり処理を長くさせれば30秒過ぎたときにタイムアウトエラーとなるはずです。
真っ先に思うロジックがsleepを使ったやり方です。

$defaultTimeout = ini_get("max_execution_time");

echo "初期タイムアウト : {$defaultTimeout}秒\n";
// タイムアウトを5秒に設定
set_time_limit(5);
$timeout = ini_get("max_execution_time");

echo "設定したタイムアウト : {$timeout}秒\n";

// 1秒づつ10回スリープさせる
for ($i = 1; $i <= 10; $i ++) {
    echo "sleep中 : {$i}秒\n";
    // 1秒スリープする
    sleep(1);
}
// 下記が出力されないはず
echo "タイムアウト失敗\n";

このロジックを実行すると、なぜかタイムアウトしません。

————————————
初期タイムアウト : 30秒
設定したタイムアウト : 5秒
sleep中 : 1秒
sleep中 : 2秒
sleep中 : 3秒
sleep中 : 4秒
sleep中 : 5秒
sleep中 : 6秒
sleep中 : 7秒
sleep中 : 8秒
sleep中 : 9秒
sleep中 : 10秒
タイムアウト失敗
————————————

Sleepがダメかと思ってfile_get_contents()やcurlを使ってダミーAPIで遅延を発生させてもタイムアウトしませんでした。

理由はsleep()やfile_get_contents()などの関数はタイムアウト時間に含めない仕様

さっさと公式サイトの注釈を読めば早かったです。公式サイトに下記のように書かれています。

Both set_time_limit(…) and ini_set(‘max_execution_time’,…); won’t count the time cost of sleep,file_get_contents,shell_exec,mysql_query etc, so i build this function my_background_exec(), to run static method/function in background/detached process and time is out kill it:
https://www.php.net/manual/ja/function.set-time-limit.php

翻訳
set_time_limit(…)とini_set( ‘max_execution_time’、…)の両方。スリープ、file_get_contents、shell_exec、mysql_queryなどの時間コストは考慮しないので、このメソッドmy_background_exec()をビルドして、バックグラウンド/分離プロセスで静的メソッド/関数を実行し、タイムアウトにするとタイムアウトになります。

つまりsleep(1)やfile_get_contents($url)などを使って処理を遅くしても、タイムアウト時間としてカウントしてくれていないということです。

プログラムの遅延を起こすには、複雑な演算をするとかしないとタイムアウトを発生させることができません。だからと言って無限ループで・・・という発想もおかしいですが、結構難しいですね。

WIndows環境はちゃんとカウントされる

ちなみに、Windows環境でプログラムを動作させている(例えばXammp)場合は、sleep(1)やfile_get_contents($url)などの停止時間もカウントされるようです。

MacだったりLinux環境だと、カウントされませんので注意が必要です。

最後に

原因がわかるまで4時間ほどかかりました。ネット上には普通にset_time_limit()でタイムアウトする書き込みがありますが、MacやLinux環境の場合はネットの情報はあてにならなかったです。

困ったら、公式サイトを翻訳してちゃんと読んだ方が良いですね。勉強になりました。

コメント

コメントを残す

お名前(任意)
コメント:新規