Rails3とPostgreSQLで開発している時に一定時間アクセス間隔が広がった時に以下のようなエラーが出てとても困っていた。
PGError: server closed the connection unexpectedly
エラー発生後にF5でリロードすると難なく動き出すんだけど、さすがにこの現象は放置できないので、moroと深追いしてみてやっとしっぽをつかんだ。
原因は"Railsのアプリケーションサーバーを起動したままPostgreSQLのサーバーを再起動する"というもの。自分の場合はpgpool-IIを使っていて、コネクションプールの管理の部分でクライアントの接続を一度切り離しているっぽい(深追い途中)。Rails側で問題っぽいコードはは
activerecord-3.0.3/lib/active_record/connection_adapters/postgresql_adapter.rb
の active? の部分で
def active? if @connection.respond_to?(:status) @connection.status == PGconn::CONNECTION_OK else # We're asking the driver, not Active Record, so use @connection.query instead of #query @connection.query 'SELECT 1' true end # postgres-pr raises a NoMethodError when querying if no connection is available. rescue PGError, NoMethodError false end
みたいな感じでコネクションの状態を確認してるんだけど、DBを再起動した場合は最初の @connection.status の判定が通ってしまい、この後の処理で接続エラーという流れ。問答無用に @connection.query を発行してヘルスチェックをするようにしたら、この現象は発生しなくなった。
とりあえず、アプリケーションで出来ることとしては、Railsで必ず一度は呼ばれるような login 周りの処理で上記のエラーが発生したら
Activerecode::Base.connection.reconnect!
を実行してから retry という方法でお茶濁し。今まで MySQL を使うことが多くて、こういった現象には遭遇しなかったんだけど、世の PostgreSQL フリークの人は困ってないのかなあ。
Railsの3になってからわからないんですが、<br>2.3のころはpassengerなどでインスタンスが立ち上がっている間は<br>PostgreSQLは再起動不可です。<br>ウェブサーバを落としてしまってからじゃないと<br>PostgreSQLは再起動できないです。<br>だからPostgreSQLの再起動は結構な手間の作業になると思います。
確かに passenger で動かしている時は postgres は落とせませんよねえ。pgpool との合わせ技でなにか起きているような気がしますねえ。