diff --git a/lib/solid_cache/store/failsafe.rb b/lib/solid_cache/store/failsafe.rb index ec06bc0..4112019 100644 --- a/lib/solid_cache/store/failsafe.rb +++ b/lib/solid_cache/store/failsafe.rb @@ -5,6 +5,7 @@ class Store module Failsafe TRANSIENT_ACTIVE_RECORD_ERRORS = [ ActiveRecord::AdapterTimeout, + ActiveRecord::ConnectionFailed, ActiveRecord::ConnectionNotEstablished, ActiveRecord::Deadlocked, ActiveRecord::LockWaitTimeout, diff --git a/test/test_helper.rb b/test/test_helper.rb index b2e6d89..a04a55e 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -95,12 +95,20 @@ def shard_keys(cache, shard) shard_keys.map { |key| key.delete_prefix("#{@namespace}:") } end - def emulating_timeouts + def emulating_errors(error_class) ar_methods = [ :select_all, :delete, :exec_insert_all ] stub_matcher = ActiveRecord::Base.connection.class.any_instance - ar_methods.each { |method| stub_matcher.stubs(method).raises(ActiveRecord::StatementTimeout) } + ar_methods.each { |method| stub_matcher.stubs(method).raises(error_class) } yield ensure ar_methods.each { |method| stub_matcher.unstub(method) } end + + def emulating_timeouts(&block) + emulating_errors(ActiveRecord::StatementTimeout, &block) + end + + def emulating_connection_failures(&block) + emulating_errors(ActiveRecord::ConnectionFailed, &block) + end end diff --git a/test/unit/solid_cache_test.rb b/test/unit/solid_cache_test.rb index 2376345..8b49f8e 100644 --- a/test/unit/solid_cache_test.rb +++ b/test/unit/solid_cache_test.rb @@ -89,6 +89,32 @@ def emulating_unavailability end end +class SolidCacheConnectionFailedFailsafeTest < ActiveSupport::TestCase + include FailureSafetyBehavior + + setup do + @cache = nil + @namespace = "test-#{SecureRandom.hex}" + + @cache = lookup_store(expires_in: 60) + # @cache.logger = Logger.new($stdout) # For test debugging + + # For LocalCacheBehavior tests + @peek = lookup_store(expires_in: 60) + end + + # A terminated connection raises ActiveRecord::ConnectionFailed, which is a + # subclass of ActiveRecord::StatementInvalid rather than of + # ActiveRecord::ConnectionNotEstablished, so it needs its own failsafe entry. + # Regression test for https://github.com/rails/solid_cache/issues/307. + def emulating_unavailability + wait_for_background_tasks(@cache) + emulating_connection_failures do + yield lookup_store(namespace: @namespace) + end + end +end + class SolidCacheRaisingTest < ActiveSupport::TestCase include FailureRaisingBehavior