diff options
author | schneems <richard.schneeman+foo@gmail.com> | 2018-09-20 13:56:07 -0500 |
---|---|---|
committer | schneems <richard.schneeman+foo@gmail.com> | 2018-09-20 15:31:38 -0500 |
commit | 135d3e15b72b9820212027b057df8980140a947b (patch) | |
tree | 3d2b41d17c4603aced3a9d414af27327b95e2229 | |
parent | b45b96b91fc62e7488002cb05c96ec78577f7873 (diff) | |
download | rails-135d3e15b72b9820212027b057df8980140a947b.tar.gz rails-135d3e15b72b9820212027b057df8980140a947b.tar.bz2 rails-135d3e15b72b9820212027b057df8980140a947b.zip |
[close #33907] Error when using "recyclable" cache keys with a store that does not support it
If you are using the "in cache versioning" also known as "recyclable cache keys" the cache store must be aware of this scheme, otherwise you will generate cache entries that never invalidate.
This PR adds a check to the initialization process to ensure that if recyclable cache keys are being used via
```
config.active_record.cache_versioning = true
```
Then the cache store needs to show that it supports this versioning scheme. Cache stores can let Rails know that they support this scheme by adding a method `supports_in_cache_versioning?` and returning true.
-rw-r--r-- | activerecord/lib/active_record/railtie.rb | 23 | ||||
-rw-r--r-- | activesupport/lib/active_support/cache/file_store.rb | 7 | ||||
-rw-r--r-- | activesupport/lib/active_support/cache/mem_cache_store.rb | 7 | ||||
-rw-r--r-- | activesupport/lib/active_support/cache/memory_store.rb | 7 | ||||
-rw-r--r-- | activesupport/lib/active_support/cache/null_store.rb | 7 | ||||
-rw-r--r-- | activesupport/lib/active_support/cache/redis_cache_store.rb | 7 | ||||
-rw-r--r-- | railties/CHANGELOG.md | 5 | ||||
-rw-r--r-- | railties/test/application/configuration_test.rb | 12 |
8 files changed, 75 insertions, 0 deletions
diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb index b213754641..fcee3de0b7 100644 --- a/activerecord/lib/active_record/railtie.rb +++ b/activerecord/lib/active_record/railtie.rb @@ -88,6 +88,29 @@ module ActiveRecord end end + initializer "Check for cache versioning support" do + config.after_initialize do |app| + ActiveSupport.on_load(:active_record) do + if app.config.active_record.cache_versioning && Rails.cache + unless Rails.cache.try(:supports_in_cache_versioning?) + raise <<-end_error + +You're using a cache store `#{Rails.cache.class}` that does not support +"recyclable" cache keys, also known as "in cache versioning". To +fix this issue either disable "recyclable" cache keys by setting: + + config.active_record.cache_versioning = false + +Or switching to a cache store that supports this functionality: +https://guides.rubyonrails.org/caching_with_rails.html#cache-stores + +end_error + end + end + end + end + end + initializer "active_record.check_schema_cache_dump" do if config.active_record.delete(:use_schema_cache_dump) config.after_initialize do |app| diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb index 04c54c30d0..b17f0a4a4a 100644 --- a/activesupport/lib/active_support/cache/file_store.rb +++ b/activesupport/lib/active_support/cache/file_store.rb @@ -26,6 +26,13 @@ module ActiveSupport @cache_path = cache_path.to_s end + # Advertise that this cache store can be used + # with "recyclable cache keys" otherwise known + # as cache versioning. + def supports_in_cache_versioning? + true + end + # Deletes all items from the cache. In this case it deletes all the entries in the specified # file store directory except for .keep or .gitkeep. Be careful which directory is specified in your # config file when using +FileStore+ because everything in that directory will be deleted. diff --git a/activesupport/lib/active_support/cache/mem_cache_store.rb b/activesupport/lib/active_support/cache/mem_cache_store.rb index 2840781dde..f235f05d6c 100644 --- a/activesupport/lib/active_support/cache/mem_cache_store.rb +++ b/activesupport/lib/active_support/cache/mem_cache_store.rb @@ -47,6 +47,13 @@ module ActiveSupport end end + # Advertise that this cache store can be used + # with "recyclable cache keys" otherwise known + # as cache versioning. + def supports_in_cache_versioning? + true + end + prepend Strategy::LocalCache prepend LocalCacheWithRaw diff --git a/activesupport/lib/active_support/cache/memory_store.rb b/activesupport/lib/active_support/cache/memory_store.rb index 564ac17241..32530fa2a9 100644 --- a/activesupport/lib/active_support/cache/memory_store.rb +++ b/activesupport/lib/active_support/cache/memory_store.rb @@ -30,6 +30,13 @@ module ActiveSupport @pruning = false end + # Advertise that this cache store can be used + # with "recyclable cache keys" otherwise known + # as cache versioning. + def supports_in_cache_versioning? + true + end + # Delete all data stored in a given cache store. def clear(options = nil) synchronize do diff --git a/activesupport/lib/active_support/cache/null_store.rb b/activesupport/lib/active_support/cache/null_store.rb index 1a5983db43..405d485671 100644 --- a/activesupport/lib/active_support/cache/null_store.rb +++ b/activesupport/lib/active_support/cache/null_store.rb @@ -12,6 +12,13 @@ module ActiveSupport class NullStore < Store prepend Strategy::LocalCache + # Advertise that this cache store can be used + # with "recyclable cache keys" otherwise known + # as cache versioning. + def supports_in_cache_versioning? + true + end + def clear(options = nil) end diff --git a/activesupport/lib/active_support/cache/redis_cache_store.rb b/activesupport/lib/active_support/cache/redis_cache_store.rb index 5737450b4a..4cee774908 100644 --- a/activesupport/lib/active_support/cache/redis_cache_store.rb +++ b/activesupport/lib/active_support/cache/redis_cache_store.rb @@ -66,6 +66,13 @@ module ActiveSupport SCAN_BATCH_SIZE = 1000 private_constant :SCAN_BATCH_SIZE + # Advertise that this cache store can be used + # with "recyclable cache keys" otherwise known + # as cache versioning. + def supports_in_cache_versioning? + true + end + # Support raw values in the local cache strategy. module LocalCacheWithRaw # :nodoc: private diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index 691e599ddb..da4beedecf 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,3 +1,8 @@ +* Raise an error when "recyclable cache keys" are being used by a cache store + that does not explicitly support it. + + *Richard Schneeman* + * Support environment specific credentials file. For `production` environment look first for `config/credentials/production.yml.enc` file that can be decrypted by diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index 11cd6dd1e6..386b4f76e6 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -124,6 +124,18 @@ module ApplicationTests assert_equal "MyLogger", Rails.application.config.logger.class.name end + test "raises an error if cache does not support recyclable cache keys" do + build_app(initializers: true) + add_to_env_config "production", "config.cache_store = Class.new {}.new" + add_to_env_config "production", "config.active_record.cache_versioning = true" + + error = assert_raise(RuntimeError) do + app "production" + end + + assert_match(/You're using a cache store/, error.message) + end + test "a renders exception on pending migration" do add_to_config <<-RUBY config.active_record.migration_error = :page_load |