Skip to content

Instantly share code, notes, and snippets.

@cha55son
Last active July 19, 2017 05:10
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cha55son/2486a6b10374f12387e2a4e9a1e194c4 to your computer and use it in GitHub Desktop.
Save cha55son/2486a6b10374f12387e2a4e9a1e194c4 to your computer and use it in GitHub Desktop.
Disable Rails 5 Connection Pool
# config/application.rb
require_relative 'boot'
require 'rails/all'
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
module MyApp
class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
end
end
require_relative "../lib/connection_pool"
ActiveRecord::ConnectionAdapters::ConnectionPool = ConnectionPool
# config/initializers/db_setup.rb
Rails.application.config.after_initialize do
ActiveSupport.on_load(:active_record) do
ActiveRecord::Base.establish_connection(
adapter: <adapter type>,
data_source: <pooled_data_source>,
)
end
end
# lib/connection_pool.rb
require 'thread'
require 'concurrent/map'
require 'monitor'
require_relative 'reaper'
require_relative 'queue'
# Following the contract supplied by ConnectionPool
# http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/ConnectionPool.html
class ConnectionPool
include MonitorMixin
include ActiveRecord::ConnectionAdapters::QueryCache::ConnectionPoolConfiguration
attr_accessor :automatic_reconnect, :checkout_timeout, :schema_cache
attr_reader :spec, :connections, :size, :reaper
def initialize(spec)
trace "ConnectionPool.initialize", 5
super()
@spec = spec
@checkout_timeout = (spec.config[:checkout_timeout] && spec.config[:checkout_timeout].to_f) || 5
@reaper = Reaper.new(self, (spec.config[:reaping_frequency] && spec.config[:reaping_frequency].to_f))
@reaper.run
@size = (spec.config[:pool] && spec.config[:pool].to_i) || 5
@thread_cached_conns = Concurrent::Map.new
@connections = []
@automatic_reconnect = true
@now_connecting = 0
@threads_blocking_new_connections = 0
@available = Queue.new
@lock_thread = false
end
def lock_thread=(lock_thread)
trace "ConnectionPool.lock_thread"
if lock_thread
@lock_thread = Thread.current
else
@lock_thread = nil
end
end
def connection
trace "ConnectionPool.connection"
@thread_cached_conns[connection_cache_key(@lock_thread || Thread.current)] ||= checkout
end
def active_connection?
trace "ConnectionPool.active_connection?"
@thread_cached_conns[connection_cache_key(Thread.current)]
end
def release_connection(owner_thread = Thread.current)
trace "ConnectionPool.release_connection"
if conn = @thread_cached_conns.delete(connection_cache_key(owner_thread))
checkin conn
end
end
def with_connection
trace "ConnectionPool.with_connection"
unless conn = @thread_cached_conns[connection_cache_key(Thread.current)]
conn = connection
fresh_connection = true
end
yield conn
ensure
release_connection if fresh_connection
end
def connected?
trace "ConnectionPool.connected?"
synchronize { @connections.any? }
end
def disconnect(raise_on_acquisition_timeout = true)
trace "ConnectionPool.disconnect"
synchronize do
@connections.each do |conn|
if conn.in_use?
conn.steal!
checkin conn
end
conn.disconnect!
end
@connections = []
@available.clear
end
end
def disconnect!
trace "ConnectionPool.disconnect!"
disconnect(false)
end
def clear_reloadable_connections(raise_on_acquisition_timeout = true)
trace "ConnectionPool.clear_reloadable_connections"
synchronize do
@connections.each do |conn|
if conn.in_use?
conn.steal!
checkin conn
end
conn.disconnect! if conn.requires_reloading?
end
@connections.delete_if(&:requires_reloading?)
@available.clear
end
end
def clear_reloadable_connections!
trace "ConnectionPool.clear_reloadable_connections!"
clear_reloadable_connections(false)
end
def checkout(checkout_timeout = @checkout_timeout)
trace "ConnectionPool.checkout"
conn = checkout_new_connection
conn.lease
checkout_and_verify(conn)
end
def checkin(conn)
trace "ConnectionPool.checkin"
synchronize do
remove_connection_from_thread_cache conn
conn._run_checkin_callbacks do
conn.expire
end
@available.add conn
end
end
def remove(conn)
trace "ConnectionPool.remove"
synchronize do
remove_connection_from_thread_cache conn
@connections.delete conn
@available.delete conn
end
end
def reap
trace "ConnectionPool.reap"
end
def num_waiting_in_queue
trace "ConnectionPool.num_waiting_in_queue"
@available.num_waiting
end
def stat
trace "ConnectionPool.stat"
{}
end
private
def connection_cache_key(thread)
thread
end
def remove_connection_from_thread_cache(conn, owner_thread = conn.owner)
@thread_cached_conns.delete_pair(connection_cache_key(owner_thread), conn)
end
alias_method :release, :remove_connection_from_thread_cache
def checkout_new_connection
conn = new_connection
conn.pool = self
@connections << conn
conn
end
def new_connection
ActiveRecord::Base.send(spec.adapter_method, spec.config).tap do |conn|
conn.schema_cache = schema_cache.dup if schema_cache
end
end
def checkout_and_verify(c)
c._run_checkout_callbacks do
c.verify!
end
c
rescue
remove c
c.disconnect!
raise
end
def trace(msg, depth = 1)
puts msg
caller[1..depth].each do |line|
puts " \\---> #{line}"
end
end
end
# lib/connection_poll/queue.rb
require 'monitor'
class ConnectionPool
class Queue
include MonitorMixin
def initialize(lock = Monitor.new)
@lock = lock
@cond = @lock.new_cond
@num_waiting = 0
@queue = []
end
# Returns the number of threads currently waiting on this
# queue.
def num_waiting
synchronize do
@num_waiting
end
end
# Add +element+ to the queue. Never blocks.
def add(element)
synchronize do
@queue.push element
@cond.signal
end
end
# If +element+ is in the queue, remove and return it, or +nil+.
def delete(element)
synchronize do
@queue.delete(element)
end
end
# Remove all elements from the queue.
def clear
synchronize do
@queue.clear
end
end
private
def synchronize(&block)
@lock.synchronize(&block)
end
end
end
# lib/connection_pool/reaper.rb
class ConnectionPool
class Reaper
attr_reader :pool, :frequency
def initialize(pool, frequency)
@pool = pool;
@frequency = frequency;
end
def run; end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment