PHPでファイルのダウンロードやアップロード、外部APIへのリクエストを行うと、それらの処理中に他のリクエストが処理できなくなる事象が発生する場合があります。
発生条件
- ログインを必要とするシステムである。あるいは、ログインは行わないが、セッションの利用を行うシステムである。
- ファイルをダウンロード(またはアップロード中)、あるいは外部APIへのリクエストを行っている。また、処理時間のかかる(長い)処理である。
- 上記処理中に他の処理を行おうとすると(例えば同じシステム内の別機能を呼び出そうとすると)、結果が表示されるまでに時間がかかったり、タイムアウトする。
- 上記処理が完了あるいは中断後は、正常に他の処理を呼び出せるようになる。
- 上記処理中に、別ブラウザ(あるいは同一ブラウザのシークレットモード)から同じシステムへログインし、別機能を呼び出した場合は、当該事象(結果が表示されるまでに時間がかかる、タイムアウトする)は発生しない(=同一セッションでは発生するが、別セッションでは発生しない)。
- セッションを利用しない機能では、当該事象は発生しない。
原因
セッションが排他ロックされているためです。
session_start()
を呼び出すと、処理が完了されるか、明示的にセッションをクローズするまでの間、セッションがオープンされたままとなり、その間、排他ロックされます。
ほとんどの処理(すぐに完了する処理)においては、排他ロックによる影響を意識する必要はありませんが、ファイルのダウンロードやアップロード、あるいは外部APIへのリクエスト等、処理時間が長くなりがちな処理においては、排他ロックの影響について考慮する必要があります。
対応方法
ファイルのダウンロードやアップロード、時間のかかる外部APIへのリクエストを行う前に、セッションを明示的にクローズします。
※上記処理に必要となる値がセッションに格納されている場合は、セッションをクローズする前に取得し、変数や配列に格納しておきます。
session_write_close()
を、時間のかかる処理の前に実行します。
参考:https://www.php.net/manual/ja/function.session-write-close.php
もし、処理完了後にセッションを参照したり、セッションデータを書き込みたい場合は、 処理完了後にsession_start()
してセッションを再開してから、セッションデータの参照や書き込みを行います。
参考:https://www.php.net/manual/ja/function.session-start.php
なお、セッションをクローズすることによって、セッションデータがクリアされることはありません。
また、上記はいずれもPHP標準メソッドになります。フレームワークを利用している場合は、フレームワークごとに実装は異なりますので、フレームワークのドキュメントより関連する内容を確認して対応してください。