PHP ロングポーリングとセッションのデッドロックについて

今回、なかなかレアなケースだと思いますが、致命的な現象に出会ったのでメモ。

やりたかったこと

トーク画面のようなwebサービスを実装しようと思い、ロングポーリングというアーキテクチャをPHPとjsで実装しました。

ロングポーリングとは掲示板などで更新があった際にそれをリアルタイムで表示する等、サーバと常に同期をとるような処理を実装するための考え方です。

クライアントがリクエストを送信後、サーバ側は何らかのデータ更新が発生するまでループ処理を行い、更新が発生した時点でレスポンスを返します。クライアント側はレスポンスが帰ってきた場合は何らかの処理を行い再度リクエストを投げます。レスポンスが帰ってこずタイムアウトした場合はそのまま再度リクエストを送信します。

PHPのセッションデッドロック

PHPでセッションを使う際、必ずsession_start()を呼び出しますが、これを呼び出した時点でセッションファイルに排他ロックをかけるようです。もしロングポーリング処理がセッションにロックをかけると、同じセッションIDからの処理はsession_start()してもロックがかかってしまっているため、ずっと待機してしまいます。なので今回の掲示板なサービスで言えば、投稿ボタンを押して処理を投げてもレスポンスが帰ってこない状態になってしまうのです。

明示的にセッションを開放する

session_start後にセッションを使った処理を終えた後、session_write_close()を行うことで明示的にセッションを開放することができます。これでロングポーリング中にも別の処理を呼び出すことが可能となるのです。

session_start();
//セッションを使った処理。。。

//セッションの開放
session_write_close();