-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Include adapter in cache key #1644
Include adapter in cache key #1644
Conversation
9e4b5c2
to
20d9076
Compare
Questions:
|
I think this looks good. As to you're question about how they are cached differently, I had the same question when we started getting errors in production. Looking at the code, it looked like it parsed the cached attributes. We a monkey patch and test to confirm the issue. Here is the cached values from our test. For the
For
Here is our test for it:
|
Thanks so much for that! I'll be sure to add it
|
Btw, do you have any benchmarka showing caching improves performance? I
|
any way I can help you get off of that? |
@kevintyll What were your |
@kevintyll Here's how I wrote a test that fails on master. bf4@aee3118 It's not polished, but it gets the job done def test_a_serializer_rendered_by_two_adapter_returns_differently_cached_attributes
model = Class.new(ActiveModelSerializers::Model) do
attr_accessor :id, :status, :resource, :started_at, :ended_at, :updated_at, :created_at
end
Object.const_set(:Alert, model)
serializer = Class.new(ActiveModel::Serializer) do
cache
attributes :id, :status, :resource, :started_at, :ended_at, :updated_at, :created_at
end
Object.const_set(:AlertSerializer, serializer)
alert = Alert.new(
id: 1,
status: "fail",
resource: "resource-1",
started_at: Time.new(2016, 3, 31, 21, 36, 35, 0),
ended_at: nil,
updated_at: Time.new(2016, 3, 31, 21, 27, 35, 0),
created_at: Time.new(2016, 3, 31, 21, 37, 35, 0)
)
serializable_alert = serializable(alert, serializer: AlertSerializer, adapter: :attributes)
attributes_serialization1 = serializable_alert.as_json
assert_equal alert.status, attributes_serialization1.fetch(:status)
serializable_alert = serializable(alert, serializer: AlertSerializer, adapter: :attributes)
attributes_serialization2 = serializable_alert.as_json
assert_equal attributes_serialization1, attributes_serialization2
attributes_cache_key = CachedSerializer.new(serializable_alert.adapter.serializer).cache_key
assert_equal attributes_serialization1, cache_store.fetch(attributes_cache_key)
serializable_alert = serializable(alert, serializer: AlertSerializer, adapter: :json_api)
jsonapi_cache_key = CachedSerializer.new(serializable_alert.adapter.serializer).cache_key
refute_equal attributes_cache_key, jsonapi_cache_key
jsonapi_serialization1 = serializable_alert.as_json
assert_equal alert.status, jsonapi_serialization1.fetch(:data).fetch(:attributes).fetch(:status)
serializable_alert = serializable(alert, serializer: AlertSerializer, adapter: :json_api)
jsonapi_serialization2 = serializable_alert.as_json
assert_equal jsonapi_serialization1, jsonapi_serialization2
cached_serialization = cache_store.fetch(jsonapi_cache_key)
assert_equal jsonapi_serialization1, cached_serialization
expected_jsonapi_serialization = {
id: "1",
type: "alerts",
attributes: {
created_at: 'Thu, 31 Mar 2016 21:37:35 UTC +00:00',
status: "fail",
resource: "resource-1",
updated_at: 'Thu, 31 Mar 2016 21:37:35 UTC +00:00',
started_at: 'Thu, 31 Mar 2016 21:36:35 UTC +00:00',
ended_at: nil}
}
assert_equal expected_jsonapi_serialization, jsonapi_serialization1
ensure
Object.send(:remove_const, :Alert)
Object.send(:remove_const, :AlertSerializer)
end when the cache key is the same for both adapters, after serializing with the attributes adapter, trying to serialize with the jsonapi adapter blows up since the cache value it expects is in the format of Running
And if I jsonapi_cache_key = CachedSerializer.new(serializable_alert.adapter.serializer).cache_key
+ cached_serialization = cache_store.fetch(jsonapi_cache_key)
+ p [attributes_cache_key, jsonapi_cache_key, attributes_serialization2 == cached_serialization]
refute_equal attributes_cache_key, jsonapi_cache_key I get confirmation the keys are the same and the values are the same.
running on this branch with that test added I get
(with the necessary change: - attributes_cache_key = CachedSerializer.new(serializable_alert.adapter.serializer).cache_key
+ attributes_cache_key = CachedSerializer.new(serializable_alert.adapter.serializer).cache_key(serializable_alert.adapter)
assert_equal attributes_serialization1, cache_store.fetch(attributes_cache_key)
serializable_alert = serializable(alert, serializer: AlertSerializer, adapter: :json_api)
- jsonapi_cache_key = CachedSerializer.new(serializable_alert.adapter.serializer).cache_key
+ jsonapi_cache_key = CachedSerializer.new(serializable_alert.adapter.serializer).cache_key(serializable_alert.adapter)
cached_serialization = cache_store.fetch(jsonapi_cache_key)
p [attributes_cache_key, jsonapi_cache_key, attributes_serialization2 == cached_serialization] |
20d9076
to
b3d0e90
Compare
… adapter Adapted from @kevintyll's original test rails-api#1644 (comment)
Confirm caching attributes with different key json_api vs. attributes adapter Adapted from @kevintyll's original test rails-api#1644 (comment)
b3d0e90
to
16a3f93
Compare
Rebased off of master |
I do not have any benchmarks. In fact, in 1 use case, we have a report object that can have thousands of child objects, because each object gets cached separately, it took “forever” to pull every object out and deserialize them and rebuild the object. We fell back to regular Rails cache in that instance and just serialized the entire object tree in a single shot.
|
As far as getting off rc3, I am waiting for the internals to stabilize. Most of our monkey patching is to extend the functionality to include the related links. I created a custom adapter that inherits the JsonApi adapter, and adds the In order to do that, I had to override a few things and create some other new classes. While the public API remains fairly stable between release candidates, the private API I'm relying on changes quite a bit between releases. I don't want to have to redo my overrides and extensions for no net benefit. I know you've added code that also now include the We are in production with what we have, so probably will stay on rc3 until 1.0 is released. I'll go through the pain of refactoring then. |
My V2::AlertSerializer cache options:
though the key gets ignored because the alert object responds to |
re: #1644 (comment)
Yeah, I haven't yet seen a case where using caching improves performance #1586 |
@kevintyll Also, I'd love to help you share back any work you've done. |
Continues work in #1346, #1642
Fixes #1344
Cherry-pick of
bf4@040a97b
which was a squash of
https://github.com/rails-api/active_model_serializers/commits/f89ed71058322fe7dd35d5c8b209856f8e03ad14