質問: 以下のようなエンドポイントを作って叩いてみたところ ``` public function get_timeout() { Log::error(ini_get('max_execution_time')); set_time_limit(10); Log::error(ini_get('max_execution_time')); sleep(60); return $this->response('ok', 200); } ``` ログには ``` ERROR - 2019-10-12 03:10:47 --> 30 ERROR - 2019-10-12 03:10:47 --> 10 ``` とでて max_execution_time は変更されてるんですが ``` time curl http://localhost/api/test/timeout curl http://localhost/api/test/timeout 0.01s user 0.01s system 0% cpu 1:00.15 total ``` となって1分たつまで結果が帰ってきません 次に curl を途中で Ctrl+Cで終了したところ サーバー側では 60 秒たってから httpd のログに 200 扱いで記録されます Apache の設定では ``` Timeout 10 ``` となってるんですがいずれも反映されてないように見えます PHP内で時間がかかった場合に途中で打ち切ってエラーを返すことってできないんでしょうか
回答: PHP: set_time_limit - Manual PHPのドキュメントを参照すると > > このスクリプト自体の実行時間にのみ影響を与えます。 system() を用いたシステムコール、ストリーム操作、 > > データベースクエリ等のスクリプト実行以外で発生する処理にかかった時間は スクリプトが実行される最大時間を定義する際には含まれません > > > とあります。PHPのスクリプトにかかった時間だけ計測されてtimeoutが発生することになります。 sleepはCPUも使わないし、リソースの消費がないのでタイムアウトからは除外されることになります。 そこで大事なことは本番のスクリプトではsleepをしてタイムアウトを検出することはないと思います。 実際はsleepの部分を別の処理に置き換えることになると思いますが、それが何によるかでタイムアウトが発生するか決まってきます。 純粋なPHPの処理であればタイムアウトは設定できています。 それ以外の処理であるならば何らか対策が必要です。 システムコールやデータベースなどの外部システムの場合は、オプションで設定できることもありますが、 なければPHP側で外部システム呼び出しをバックグラウンド処理に変更して秒数の計測をする必要があります。 ストリーム処理であれば専用の関数を利用してください。 PHP: stream_set_timeout - Manual またお試しでタイムアウトを発生させたければsleepではなく(リソースの使用状況に気をつけて)無限ループを利用して試してみると良いでしょう。