I'm seeing some performance issues in my application and was wondering whether my cache was working properly or if I misunderstood / misconfigured anything. I'm using fast-jsonapi for serialization which comes with a built-in caching option.
Let's say:
class BooksController < ApplicationController
...
def index
@books = Books.includes(:author, :publisher).with_attached_cover.all
BookSerializer.new(@book, { include: [:author, :publisher]}).serializable_hash.to_json
end
...
end
and
class BookSerializer
include FastJsonapi::ObjectSerializer
cache_options store: Rails.cache, namespace: 'fast-jsonapi', expires_in: 24.hours
belongs_to :author
belongs_to :publisher
attributes :all_the_book_attributes_im_too_lazy_to_list
end
also let's assume I have around 5000 books of 2000 authors and 100 publishers, so I would expect caching to make a big difference in performance.
However, in fact I'm seeing my database hit the same way with or without caching enabled and really slow response times. Further, when checking my cache it only seems to be caching each individual book but not the serialized hash as a whole.
Now I'm wondering whether I completely missed the purpose of caching in a serializer or if I need to add some additional layer in my controller? If yes, is there a solution to do so in a DRY way? Would it conflict with the cache of the serializer? What is the purpose of a cache in a serializer then anyway?
I know that there are multiple ways/layers of cache I can use. I'm just not sure which ones to combine and whether to prevent any conflicts between those layers.
Like I can see you want to cache this JSON response.
Add a cache key for this query. You need this to invalidate the response, when books change over the time.
# model book.rb
class Book < ApplicationRecord
...
def self.cache_key
{
serializer: 'books',
stat_record: Book.maximum(:updated_at)
}
end
...
end
In your controller use that key to get the data from the cache OR make a new query:
class BooksController < ApplicationController
...
def index
@books = Rails.cache.fetch(Book.cache_key) do
BookSerializer.new(
Books.includes(:author, :publisher).with_attached_cover.all,
{
include: [:author, :publisher]
}
).serializable_hash.to_json
end
render json: @books
end
...
end
You can also have a look at page caching.
And btw if you have 5000 entries you should think of pagination.