接続状態の確認に connected? を優先使用
Rails 8.1では、データベース接続の有効性チェックにおいて、より正確な状態判定を行うようになりました。
背景
これまで with_raw_connection メソッドでは、接続が nil かどうかのみをチェックしていましたが、これでは接続が確立されているものの使用不可能な状態(例:ネットワーク切断後など)を検出できませんでした。#56657 では、connected? メソッドを使用することで、より包括的な接続状態の判定を実現しています。
技術的な変更
AbstractAdapterの修正
変更前:
def with_raw_connection(allow_retry: false, materialize_transactions: true)
@lock.synchronize do
connect! if @raw_connection.nil? && reconnect_can_restore_state?
# ...
end
end
変更後:
def with_raw_connection(allow_retry: false, materialize_transactions: true)
@lock.synchronize do
connect! if !connected? && reconnect_can_restore_state?
# ...
end
end
PostgreSQLアダプターの強化
PostgreSQLアダプターでは、connected? メソッドがより詳細な状態チェックを行うようになりました:
def connected?
!(@raw_connection.nil? || @raw_connection.finished? || @raw_connection.status != PG::CONNECTION_OK)
end
これにより、以下の3つの条件すべてをクリアしている場合のみ「接続中」と判定されます:
-
@raw_connectionが存在する - 接続が終了していない(
finished?が false) - PostgreSQLの接続ステータスが
PG::CONNECTION_OK
active?メソッドの改善
active? メソッドも connected? を使用するように変更されました:
def active?
@lock.synchronize do
return false unless connected?
@raw_connection.query ";"
verified!
end
end
これにより、active? の呼び出し時に接続状態を即座に判定し、不正な接続として記録できるようになります。
設計判断
この変更の重要なポイントは、接続が使用不可能になったことを検出したら、その状態を記憶するという点です。PR説明にあるように、「新たな切断をリアルタイムで検出するわけではない」ものの、一度問題が検出された接続については、以降の処理で不要な再試行を避けることができます。
テストの分割が必要になった理由は、active? の呼び出しが接続を「不正」としてマークするようになったためです。以前のテストでは、active? チェック後に自動的に接続が回復してしまい、意図したテストケースを実行できなくなっていました。
新しいテストケースでは、以下の動作を確認しています:
test "active? on a 'clean' recently-used but now-failed connection detects but doesn't fix the problem" do
remote_disconnect @connection
@connection.clean! # プールからの新規チェックアウトをシミュレート
# cleanメソッドは接続を検証・修正しない
assert_not_predicate @connection, :active?
# active?チェックも接続を修正しない
assert_not_predicate @connection, :active?
end
これにより、接続プールから取り出された接続が実際には使用不可能だった場合、それを検出できるが自動修復はしない、という挙動が保証されます。過度な再検証を避けつつ、明示的なエラー処理を促す設計となっています。