Merge pull request #49802 from composerinteralia/postgres-unrecoverable-connection-error

Recover from failed connections in PostgreSQL
This commit is contained in:
Matthew Draper 2023-11-06 17:26:11 +10:30 committed by GitHub
commit c0e67e6547
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 29 additions and 17 deletions

@ -903,10 +903,10 @@ def exec_cache(sql, name, binds, async:, allow_retry:, materialize_transactions:
update_typemap_for_default_timezone
stmt_key = prepare_statement(sql, binds)
type_casted_binds = type_casted_binds(binds)
with_raw_connection do |conn|
stmt_key = prepare_statement(sql, binds, conn)
type_casted_binds = type_casted_binds(binds)
log(sql, name, binds, type_casted_binds, stmt_key, async: async) do
conn.exec_prepared(stmt_key, type_casted_binds)
end
@ -956,22 +956,20 @@ def sql_key(sql)
# Prepare the statement if it hasn't been prepared, return
# the statement key.
def prepare_statement(sql, binds)
with_raw_connection(allow_retry: true, materialize_transactions: false) do |conn|
sql_key = sql_key(sql)
unless @statements.key? sql_key
nextkey = @statements.next_key
begin
conn.prepare nextkey, sql
rescue => e
raise translate_exception_class(e, sql, binds)
end
# Clear the queue
conn.get_last_result
@statements[sql_key] = nextkey
def prepare_statement(sql, binds, conn)
sql_key = sql_key(sql)
unless @statements.key? sql_key
nextkey = @statements.next_key
begin
conn.prepare nextkey, sql
rescue => e
raise translate_exception_class(e, sql, binds)
end
@statements[sql_key]
# Clear the queue
conn.get_last_result
@statements[sql_key] = nextkey
end
@statements[sql_key]
end
# Connects to a PostgreSQL server and sets up the adapter depending on the

@ -612,6 +612,20 @@ def teardown
assert_predicate @connection, :active?
end
test "querying after a failed query restores and succeeds" do
Post.first # Connection verified (and prepared statement pool populated if enabled)
remote_disconnect @connection
assert_raises(ActiveRecord::ConnectionFailed) do
Post.first # Connection no longer verified after failed query
end
assert Post.first # Verifying the connection causes a reconnect and the query succeeds
assert_predicate @connection, :active?
end
test "transaction restores after remote disconnection" do
remote_disconnect @connection
Post.transaction do