Created
July 13, 2017 07:13
-
-
Save pts-owentran/5aac9574dfc9684f47250c0df08f8d29 to your computer and use it in GitHub Desktop.
You can throw this into lib/core_ext in your rails app to prevent implicit connections being made with a stack trace to track down the errant code.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
###################### | |
# | |
# This is hacked from the original code for Rails 4.1. Owen went in and hacked the ConnectionPool | |
# so it's not fool proof but prevents ShopHotelsCommand from grabbing dozens of idle DB connections. | |
# | |
# If you create a thread yourself, if it uses ActiveRecord objects without | |
# explicitly checking out a connection, one will still be checked out implicitly. | |
# If it is never checked back in with `ActiveRecord::Base.clear_active_connections!`, | |
# then it will be leaked. | |
# | |
# For some uses, we want to avoid being able to do that kind of implicit checkout, | |
# force all ActiveRecord use to be via an explicit checkout using with_connection | |
# or checkout. | |
# | |
# With this monkey patch, a thread can call: | |
# | |
# ActiveRecord::Base.forbid_implicit_checkout_for_thread! | |
# | |
# And subsequently, if that thread accidentally tries to do an implicit | |
# checkout, an exception will be raised. | |
# | |
# The exception raised is defined here as ActiveRecord::ImplicitConnectionForbiddenError < ActiveRecord::ConnectionTimeoutError | |
# | |
########################## | |
module ActiveRecord | |
class Base | |
class << self | |
def forbid_implicit_checkout_for_thread! | |
Thread.current[:active_record_forbid_implicit_connections] = true | |
end | |
def permit_implicit_checkout_for_thread! | |
Thread.current[:active_record_forbid_implicit_connections] = false | |
end | |
def implicit_checkout_for_thread_forbidden? | |
Thread.current[:active_record_forbid_implicit_connections] == true | |
end | |
end | |
end | |
module ForbidImplicitConnection | |
def connection | |
if Thread.current[:active_record_forbid_implicit_connections] | |
msg = "Implicit ActiveRecord checkout attempted when Thread :active_record_forbid_implicit_connections set!" | |
backtrace = Thread.current.backtrace.join("\n") | |
# I want to make SURE I see this error in test output, even though | |
# in some cases my code is swallowing the exception. | |
if Rails.env.test? | |
$stderr.puts msg | |
$stderr.puts backtrace | |
end | |
raise ActiveRecord::ImplicitConnectionForbiddenError, msg | |
end | |
super | |
end | |
end | |
# We're refusing to give a connection when asked for. Same outcome | |
# as if the pool timed out on checkout, so let's subclass the exception | |
# used for that. | |
ImplicitConnectionForbiddenError = Class.new(::ActiveRecord::ConnectionTimeoutError) | |
end | |
ActiveRecord::ConnectionAdapters::ConnectionPool.send(:prepend, ActiveRecord::ForbidImplicitConnection) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
lol that made my day! I was reading this comment in a wtf moment too.