Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replacing ActiveRecord::ConnectionAdapters::ConnectionManagement in ActiveRecord 5

We are upgrading a Sinatra application from ActiveRecord 4 to ActiveRecord 5. Previously we had this line:

use ActiveRecord::ConnectionAdapters::ConnectionManagement

This is because connections were not being cleaned up after requests completed. Here is prior SO discussion on this topic:

  • ActiveRecord connection warning. (Database connections will not be closed automatically)
  • ActiveRecord::ConnectionTimeoutError

Starting with ActiveRecord 5, this line no longer works. This conversation in the rails project states:

This was removed in favor of Executor and Reloader APIs. That middleware that was removed were not part of the public API. If you want to use that outside Rails you need to make one.

Does this mean that, if someone is to use ActiveRecord 5 with Sinatra, connections will be again 'leaked' or left un-returned to the pool after a request, unless the developer re-creates the now-removed middleware?

In the Sinatra example, is it therefore now the case that we need to include this line in ActiveRecord 5?

after do
  ActiveRecord::Base.clear_active_connections!
end

That is the implication on the linked-to thread, but I want to get a definite answer I can take back to my dev team.

like image 734
esilver Avatar asked Dec 30 '16 17:12

esilver


1 Answers

You are correct, the ConnectionManagement middleware has been removed from ActiveRecord 5 (PR #23807), so you will need to replicate similar functionality when setting up ActiveRecord outside of Rails. There are several ways to do this:

1. ConnectionManagement Rack middleware

The ConnectionManagement class is not very complicated. You can copy and paste the implementation somewhere in your local application, and include it as usual into your Rack middleware stack:

class ConnectionManagement
  def initialize(app)
    @app = app
  end

  def call(env)
    testing = env['rack.test']

    status, headers, body = @app.call(env)
    proxy = ::Rack::BodyProxy.new(body) do
      ActiveRecord::Base.clear_active_connections! unless testing
    end
    [status, headers, proxy]
  rescue Exception
    ActiveRecord::Base.clear_active_connections! unless testing
    raise
  end
end

use ConnectionManagement

2. (Sinatra-specific) connection-management after hook

Within a Sinatra app, the block you suggested should work:

after do
  ActiveRecord::Base.clear_active_connections!
end

Note that this is also the approach currently used by the sinatra-activerecord integration gem to support ActiveRecord 5 (see issue #73).

3. ActionDispatch::Executor Rack middleware

Finally, you can use the same code Rails is now using for ActiveRecord connection management by adding ActionDispatch::Executor into your Rack middleware stack, and calling ActiveRecord::QueryCache#install_executor_hooks to insert the hook used to clear ActiveRecord connections:

require 'action_dispatch/middleware/executor'
use ActionDispatch::Executor, ActiveSupport::Executor
ActiveRecord::QueryCache.install_executor_hooks
like image 197
wjordan Avatar answered Oct 21 '22 22:10

wjordan