トップ «前の日記(2011/01/20 (木) ) 最新 次の日記(2011/01/22 (土) )» 編集 RSS feed

HsbtDiary


2011/01/21 (金) [長年日記]

[rails][activerecord][pgsql] Rails3 + PostgreSQL で謎の PGError が発生する現象の対策

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 フリークの人は困ってないのかなあ。

本日のツッコミ(全2件) [ツッコミを入れる]
# xibbar (2011/01/22 (土) 05:59)

Railsの3になってからわからないんですが、<br>2.3のころはpassengerなどでインスタンスが立ち上がっている間は<br>PostgreSQLは再起動不可です。<br>ウェブサーバを落としてしまってからじゃないと<br>PostgreSQLは再起動できないです。<br>だからPostgreSQLの再起動は結構な手間の作業になると思います。

# しばた (2011/01/22 (土) 15:17)

確かに passenger で動かしている時は postgres は落とせませんよねえ。pgpool との合わせ技でなにか起きているような気がしますねえ。