Add support for caching renders in Graphiti, and better support using etags and stale?
in the controller
#424
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR exposes some things that make supporting using rails built-in caching methods like
stale?
with Graphiti a snap, and also allowing the option of caching the render of a graphiti resource (which is often the most time-consuming part of the process)Changes:
expose
cache_key
method to resource instancethis generates a combined stable cache key based on resource identifiers specified by the resource class, the specified sideloads, and any specified
extra_fields
orfields
,pages
, orlinks
which will affect the response.expose
cache_key_with_version
method to resource instancesame as above, but with the last modified dates added in. If any included resource's
updated_at
changes, this key will change.expose
updated_at
method to resource instancereturns the max
updated_at
date of the resource and any specified sideloadsexpose
etag
method to resource instancegenerate a Weak Etag based on the
cache_key_with_version
response. Withetag
andupdated_at
methods on a resource instance, usingstale?(@resource)
will respect them.for cached resources, rendering logic in Graphiti is wrapped in a cache block
Graphiti.cache.fetch("graphiti:render/#{@resource.cache_key}", version: @resource.updated_at, expires_in: @resource.expires_in ) { [expensive rendering] }
.(Using
cache_key
andversion
together by default instead of usingcache_key_with_version
as the key better ensures we won’t flood a cache store with dead keys)Using Rails etags and
stale?
You can now easily benefit from using rails etags without any additional logic by using the
stale?
method and passing in your resource.Cache the rendered json
You can also cache the json rendering-step of the resource, which in the case of json-api can sometimes be expensive. In order to cache a resource set up a cache store, enable
cache_rendering
, and then add acache_resource
directive to the resource you want to cache. For complex resources with many sideloads, this can improve your response time dramatically.Debugging
With the debug flag enabled in Graphiti config extra information will be logged. This logic tries to make caching the render loop of graphiti dead simple, but sometimes a query with an argument that changes often (a relative time, like
Time.now
for example) will create an unstable cache key, negating any potential benefits. This problems are a little tricky to spot, but the debugging code below should help.// stable key
// volatile key
The above illustrates that there have been 11 requests but only 1 of those was pulled from the cache, which in the above query's case is because the query was using
Time.now
as an argument.