Michael,
I have done some further investigating on this issue. I can reproduce
this
problem without fail. The root problem I believe is in
clear_reloadable_connections!
where it deletes the connection name from active_connections.
Patch 6928 stops sessions from building up, however, you then have the
needless
overhead of setting up a new oracle connection/session on each request.
I believe clear_reloadable_connections! should be as follows:
# Clears the cache which maps classes
def clear_reloadable_connections!
@@active_connections.each do |name, conn|
if conn.supports_reloading?
conn.disconnect!
@@active_connections.delete(name)
end
end
end
Here is my complete analysis/trace of this through the code:
After each request dispatcher.rb calls reset_after_dispatch
if you are running in development (Dependencies.mechanism == :load)
then reset_application! is called, which in turn calls:
"ActiveRecord::Base.clear_reloadable_connections! if
defined?(ActiveRecord)"
(connection_specification.rb:)
# Clears the cache which maps classes
1: def clear_reloadable_connections!
2: @@active_connections.each do |name, conn|
3: conn.disconnect! if conn.supports_reloading?
4: @@active_connections.delete(name)
5: end
6: end
notice line 4 above deletes the connection name from
active_connections.
Now when the next request comes in eventually
ActiveRecord::Base.connection
gets called. Which in turn ends up calling retrieve_connection:
1: def self.retrieve_connection #:nodoc:
2: # Name is nil if establish_connection hasn't been called for
3: # some class along the inheritance chain up to AR::Base yet.
4: if name = active_connection_name
5: if conn = active_connections[name]
6: # Verify the connection.
7: conn.verify!(@@verification_timeout)
8: elsif spec = @@defined_connections[name]
9: # Activate this connection specification.
10: klass = name.constantize
11: klass.connection = spec
12: conn = active_connections[name]
13: end
14: end
15:
16: conn or raise ConnectionNotEstablished
17: end
In this method you end up executing lines 9-12. The call to
connection= on line 11
takes you to connection_specification.rb:
# Set the connection for the class.
1: def self.connection=(spec) #:nodoc:
2: if
spec.kind_of?(ActiveRecord::ConnectionAdapters::AbstractAdapter)
3: active_connections[name] = spec
4: elsif spec.kind_of?(ConnectionSpecification)
5: config = spec.config.reverse_merge(:allow_concurrency =>
@@allow_concurrency)
7: self.connection = self.send(spec.adapter_method, config)
8: elsif spec.nil?
9: raise ConnectionNotEstablished
10: else
11: establish_connection spec
12: end
13: end
where lines 5,6 get executed. line 7 calls oracle_connection in
oracle_adapter.rb.
At this point you have 2 sessions open and will get an additional one
on each request.