From 504c513bf805d974ae5ffcf8538377049932c0f5 Mon Sep 17 00:00:00 2001 From: Matt Campbell Date: Mon, 21 Nov 2016 12:27:04 -0500 Subject: [PATCH 1/5] Allow usage with Rails 3 * lower `rails` version dependency from 4.2 to 3.2 * skip `CheckPending.class_eval` unless Rails version is >= 4 --- ...ve_record-allow_connection_failure.gemspec | 6 ++--- lib/active_record/allow_connection_failure.rb | 27 ++++++++++--------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/active_record-allow_connection_failure.gemspec b/active_record-allow_connection_failure.gemspec index 8a71199..291844d 100644 --- a/active_record-allow_connection_failure.gemspec +++ b/active_record-allow_connection_failure.gemspec @@ -20,8 +20,8 @@ Gem::Specification.new do |spec| spec.require_paths = ["lib"] spec.add_development_dependency "bundler", "~> 1.11" - spec.add_development_dependency "rake", "~> 10.0" - spec.add_development_dependency "rspec", "~> 3.0" + spec.add_development_dependency "rake", "~> 10.0" + spec.add_development_dependency "rspec", "~> 3.0" - spec.add_runtime_dependency "rails", ">= 4.2" + spec.add_runtime_dependency "rails", ">= 3.2" end diff --git a/lib/active_record/allow_connection_failure.rb b/lib/active_record/allow_connection_failure.rb index 1113c0f..2b50b88 100644 --- a/lib/active_record/allow_connection_failure.rb +++ b/lib/active_record/allow_connection_failure.rb @@ -39,17 +39,20 @@ def self.install_executor_hooks(executor = ActiveSupport::Executor) end # monkeypatches activerecord/lib/active_record/migration.rb - ActiveRecord::Migration::CheckPending.class_eval do - def call(env) - if ActiveRecord::Base.connected? && connection.supports_migrations? - mtime = ActiveRecord::Migrator.last_migration.mtime.to_i - if @last_check < mtime - ActiveRecord::Migration.check_pending!(connection) - @last_check = mtime - end - end - @app.call(env) - end - end + # CheckPending introduced after Rails 4.0 + if Rails::VERSION::MAJOR >= 4 + ActiveRecord::Migration::CheckPending.class_eval do + def call(env) + if ActiveRecord::Base.connected? && connection.supports_migrations? + mtime = ActiveRecord::Migrator.last_migration.mtime.to_i + if @last_check < mtime + ActiveRecord::Migration.check_pending!(connection) + @last_check = mtime + end + end + @app.call(env) + end + end + end end end From 999a522e039504c5b4a6b31d17ae59e810435865 Mon Sep 17 00:00:00 2001 From: Matt Campbell Date: Tue, 22 Nov 2016 12:02:17 -0500 Subject: [PATCH 2/5] Update README --- README.md | 43 +++++++++++++++++++------------------------ 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 16829b5..66ea628 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,36 @@ # ActiveRecord::AllowConnectionFailure -Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/active_record/allow_connection_failure`. To experiment with that code, run `bin/console` for an interactive prompt. +This gem monkeypatches methods inside of `ActiveRecord::QueryCache` and +`ActiveRecord::Migration::CheckPending`. -TODO: Delete this and the text above, and describe your gem +The intention is to allow a Rails application to boot without first establishing +a database connection, enabling AR's query caching mechanism, and checking for +any pending migrations. -## Installation +In practice, this is useful for situations in which you want to boot your app +and check e.g. a `/status` endpoint which does not have a database/ORM +(read: `ActiveRecord`) dependency. -Add this line to your application's Gemfile: +## Associated `Rails` PR -```ruby -gem 'active_record-allow_connection_failure' -``` - -And then execute: - - $ bundle - -Or install it yourself as: - - $ gem install active_record-allow_connection_failure +For additional context, see the associated Rails +[pull request](https://github.com/rails/rails/issues/22154). ## Usage -TODO: Write usage instructions here +Add this gem to your `Gemfile`: -## Development - -After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. - -To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). +```ruby +gem 'active_record-allow_connection_failure' +``` ## Contributing -Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/active_record-allow_connection_failure. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. - +Bug reports and pull requests are welcome on GitHub at +https://github.com/zipmark/active_record-allow_connection_failure. This project +is intended to be a safe, welcoming space for collaboration, and contributors +are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. ## License The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT). - From 72e6ddf82c64e4146f61707a0f2c39bb35dcffd1 Mon Sep 17 00:00:00 2001 From: Jake Howerton Date: Tue, 29 Nov 2016 16:17:23 -0500 Subject: [PATCH 3/5] add additional functionality to patch rails 3 --- lib/active_record/allow_connection_failure.rb | 114 ++++++++++++------ 1 file changed, 79 insertions(+), 35 deletions(-) diff --git a/lib/active_record/allow_connection_failure.rb b/lib/active_record/allow_connection_failure.rb index 2b50b88..925f2b4 100644 --- a/lib/active_record/allow_connection_failure.rb +++ b/lib/active_record/allow_connection_failure.rb @@ -5,54 +5,98 @@ module ActiveRecord module AllowConnectionFailure # monkeypatches activerecord/lib/active_record/query_cache.rb - ActiveRecord::QueryCache.class_eval do - def self.run - if ActiveRecord::Base.connected? - connection = ActiveRecord::Base.connection - enabled = connection.query_cache_enabled - connection_id = ActiveRecord::Base.connection_id - connection.enable_query_cache! - - [enabled, connection_id] + if Rails::VERSION::MAJOR == 3 + module ActiveRecord + class Base + def self.clear_cache! # :nodoc: + puts "Am I connected? #{connected?}" + connection.schema_cache.clear! if connected? + end end end - def self.complete(state) - if ActiveRecord::Base.connected? - enabled, connection_id = state - - ActiveRecord::Base.connection_id = connection_id - ActiveRecord::Base.connection.clear_query_cache - ActiveRecord::Base.connection.disable_query_cache! unless enabled + ActiveRecord::QueryCache::BodyProxy.class_eval do + def close + @target.close if @target.respond_to?(:close) + ensure + ActiveRecord::Base.connection_id = @connection_id + if ActiveRecord::Base.connected? + ActiveRecord::Base.connection.clear_query_cache + unless @original_cache_value + ActiveRecord::Base.connection.disable_query_cache! + end + end end end - def self.install_executor_hooks(executor = ActiveSupport::Executor) - executor.register_hook(self) - - executor.to_complete do - unless ActiveRecord::Base.connected? && ActiveRecord::Base.connection.transaction_open? - ActiveRecord::Base.clear_active_connections! + ActiveRecord::QueryCache.class_eval do + def call(env) + begin + if ActiveRecord::Base.connected? + old = ActiveRecord::Base.connection.query_cache_enabled + ActiveRecord::Base.connection.enable_query_cache! + end + + status, headers, body = @app.call(env) + [status, headers, ActiveRecord::QueryCache::BodyProxy.new(old, body, ActiveRecord::Base.connection_id)] + rescue Exception => e + raise e.inspect + ActiveRecord::Base.connection.clear_query_cache + unless old + ActiveRecord::Base.connection.disable_query_cache! + end + raise e end end end end + + if Rails::VERSION::MAJOR >= 4 + ActiveRecord::QueryCache.class_eval do + def self.run + if ActiveRecord::Base.connected? + connection = ActiveRecord::Base.connection + enabled = connection.query_cache_enabled + connection_id = ActiveRecord::Base.connection_id + connection.enable_query_cache! + + [enabled, connection_id] + end + end + + def self.complete(state) + if ActiveRecord::Base.connected? + enabled, connection_id = state - # monkeypatches activerecord/lib/active_record/migration.rb - # CheckPending introduced after Rails 4.0 - if Rails::VERSION::MAJOR >= 4 - ActiveRecord::Migration::CheckPending.class_eval do - def call(env) - if ActiveRecord::Base.connected? && connection.supports_migrations? - mtime = ActiveRecord::Migrator.last_migration.mtime.to_i - if @last_check < mtime - ActiveRecord::Migration.check_pending!(connection) - @last_check = mtime - end + ActiveRecord::Base.connection_id = connection_id + ActiveRecord::Base.connection.clear_query_cache + ActiveRecord::Base.connection.disable_query_cache! unless enabled + end + end + + def self.install_executor_hooks(executor = ActiveSupport::Executor) + executor.register_hook(self) + + executor.to_complete do + unless ActiveRecord::Base.connected? && ActiveRecord::Base.connection.transaction_open? + ActiveRecord::Base.clear_active_connections! + end + end + end + end + + ActiveRecord::Migration::CheckPending.class_eval do + def call(env) + if ActiveRecord::Base.connected? && connection.supports_migrations? + mtime = ActiveRecord::Migrator.last_migration.mtime.to_i + if @last_check < mtime + ActiveRecord::Migration.check_pending!(connection) + @last_check = mtime end - @app.call(env) end + @app.call(env) end end - end + end + end end From 3f17f1a2ba4a052b9b76778cde9d36ba4c13000a Mon Sep 17 00:00:00 2001 From: Jake Howerton Date: Tue, 29 Nov 2016 17:08:08 -0500 Subject: [PATCH 4/5] move AR::Base patch down --- lib/active_record/allow_connection_failure.rb | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/lib/active_record/allow_connection_failure.rb b/lib/active_record/allow_connection_failure.rb index 925f2b4..7dcc033 100644 --- a/lib/active_record/allow_connection_failure.rb +++ b/lib/active_record/allow_connection_failure.rb @@ -6,15 +6,6 @@ module ActiveRecord module AllowConnectionFailure # monkeypatches activerecord/lib/active_record/query_cache.rb if Rails::VERSION::MAJOR == 3 - module ActiveRecord - class Base - def self.clear_cache! # :nodoc: - puts "Am I connected? #{connected?}" - connection.schema_cache.clear! if connected? - end - end - end - ActiveRecord::QueryCache::BodyProxy.class_eval do def close @target.close if @target.respond_to?(:close) @@ -49,6 +40,14 @@ def call(env) end end end + + module ActiveRecord + class Base + def self.clear_cache! # :nodoc: + connection.schema_cache.clear! if connected? + end + end + end end if Rails::VERSION::MAJOR >= 4 From a4854255d2663850d729c84cb0fc662c95ad3f1a Mon Sep 17 00:00:00 2001 From: Jake Howerton Date: Tue, 29 Nov 2016 17:19:47 -0500 Subject: [PATCH 5/5] module eval for clear_cache! --- lib/active_record/allow_connection_failure.rb | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/active_record/allow_connection_failure.rb b/lib/active_record/allow_connection_failure.rb index 7dcc033..c1fd2c7 100644 --- a/lib/active_record/allow_connection_failure.rb +++ b/lib/active_record/allow_connection_failure.rb @@ -41,11 +41,9 @@ def call(env) end end - module ActiveRecord - class Base - def self.clear_cache! # :nodoc: - connection.schema_cache.clear! if connected? - end + ActiveRecord::ModelSchema::ClassMethods.module_eval do + def clear_cache! # :nodoc: + connection.schema_cache.clear! if connected? end end end