fast_jsonapi
fast_jsonapi copied to clipboard
Support different cache key method (for cache versioning from Rails 5.2)
Since Rails 5.2, it is possible to use cache versioning, see https://api.rubyonrails.org/classes/ActiveRecord/Integration.html
This means, that cache_key does not include a timestamp, but cache_version. Additionally, Rails provides cache_key_with_version (which is like cache_key in Rails <= 5.1).
I think the easiest way would be to allow the user to define a cache_key method in the serializer. For example like this:
cache_options enabled: true, cache_length: 12.hours, cache_key: :cache_key_with_version
The serializer would then call object.cache_key_with_version instead of the default object.cache_key.
What do you guys think?
@doits are you using caching in production with the gem? If yes i would be curious to see how much performance benefit it adds.
To give some more context caching in fast_jsonapi doesn't cache the record just parts of it. We don't think the serializer layer should be responsible for caching the record. So I was thinking of removing or redoing the feature in fast_jsonapi. So would love some input from someone who uses the feature.
@shishirmk I'm not using caching in production since it does not work for my Rails 5.2 apps because of the cache versioning (which I have enabled in all my apps by default). Since object.cache_key stays the same I cannot enable the cache in the serializer since it would never be refreshed (until it expires). That's why I'm asking for this change.
So I cannot help you with some performance data. I mean I can still manually enable caching for attributes like this:
attribute :something do |object|
Rails.cache.fetch("something/#{self.class.name}/#{object.cache_key_with_version}") do
... calculate something ...
end
end
... but the need was not there to do this yet. I think caching attributes (not the whole record) is a good feature for a serializer though, but of course to keep the gem simple it is up to you to remove (or refactor) it.
you can also turn it off ActiveRecord::Base.cache_versioning = false
https://api.rubyonrails.org/classes/ActiveRecord/Integration.html#method-i-cache_key
@rromanchuk turning it off will also keep the app missing the awesome feature (recyclable cache key) introduced since Rails 5.2. Also Rails 6 will turn it ON by default.
AMS also has a similar issue: https://github.com/rails-api/active_model_serializers/pull/2288
@wasifhossain yeah, i was just disabling in development.rb with bundle exec rails dev:cache to do some jsonapi sanity tests on development, i'd like to turn on some candidates to collect some data from production.
If I just want to do some limited tests, do you see any major risk of overriding #cache_key with cache_key_with_version on my AR objects? I am indeed on 5.2 with cache_versioning turned on, and using a redis LRU in production, just for caching a few collection partials, so i'm not relying on that namespace for anything explicit, i just want to make sure i'm not doing something very wrong, for example, if rails uses cache_key to construct cache_key_with_version i'm obviously going run into problems
Given that you are on rails 5.2 as well as cache_versioning is turned on, you can use cache_key to leverage the recyclable cache key concept explained in https://blog.heroku.com/cache-invalidation-rails-5-2-dalli-store. This link also lists down some criteria when cache_key may not work as expected along with some workaround.
Due to that issue, AMS had to end up in https://github.com/rails-api/active_model_serializers/pull/2288/files#diff-b762caa6dd51036307106006dd81600f, i.e. using cache_key_with_version, which would ensure the cache is properly expired. (We are using this version of AMS in production fine enough with memcached powered by this awesome addon)
So @rromanchuk, I think you can safely use cache_key_with_version in place of cache_key. The only thing you might miss in that case would be the recyclable cache key support.
I have also detailed some experiments in one of my comments there, if you are eager to look at.
Reading now, thanks for all the resources!
Oh wow, ActiveSupport::Cache::Store#read_multi doesn't support cache versioning yet?
I thought by default now rails partial collection caching uses multifetch? Does that mean all my templates are serving stale data? Just talking about vanilla rails template rendering now https://guides.rubyonrails.org/caching_with_rails.html#collection-caching
Anyways, looks like this is going to be problematic regardless, i'm guessing with out multi read/write/fetch this would be verrrrrryy slow for collections. https://github.com/Netflix/fast_jsonapi/blob/master/lib/fast_jsonapi/serialization_core.rb#L66
I'm going to read the above and educate myself.