Consider the following script:
require 'rubygems'
require 'active_record'
begin
0.upto(1000) do |i|
puts "Starting connection #{i}"
ActiveRecord::Base.establish_connection(:adapter => "postgresql",
:host => "localhost",
:database => "database",
:username => "user",
:password => "pass")
# Do something to the connection to make it actually fire up.
puts "connected" if ActiveRecord::Base.connection.active?
puts "Stopping connection #{i}"
ActiveRecord::Base.remove_connection
end
rescue
puts $!.inspect
end
What this should do is fire up and then instantaneously close 1000 database connections. It should never have more than one connection open at a time. What it actually does, against a stock postgres install, is fire up 50 connections and then fail with a postgres error on the 51st.
It's a stupid example, but a valid example of what is breaking my application.
What's causing this is the following code, in
def self.remove_connection(klass=self)
conn = @@defined_connections[klass.name]
@@defined_connections.delete(klass.name)
@@connection_cache[Thread.current.object_id].delete(klass.name)
active_connections.delete(klass.name)
@connection = nil
conn.config if conn
end
Note the absolute lack of any closing of the connection, all we do is remove it from the memory caches. It appears that, for the postgres C adaptor at least, this does not cause the actual connection to be closed.
It seems that this is related to the known issues with C language extensions and memory reclamation, similar to the need to manually run GC.start when you're done with RMagick objects; indeed, if we add GC.start to the original script after the remove_connection, all is well.
I would suggest that remove_connection is modified either to explicitly close the connection (my preferred option, as this leaves nothing to luck, but requires a little work) or at least to trigger garbage collection after clearing its caches.
Simon