Description
Regarding the issues brought up in #259...
Motivation
We'd like to make caching in JBuilder useful. Currently, caching does not offer significant performance benefits for pretty much any app. This is largely due to the serialization and over-the-wire costs JBuilder pays when storing and fetching cached content, because the current serialization scheme doesnt allow for raw partial content. Below is a proposal for enabling much faster caching while still retaining MultiJson as the serialization backend:
Proposal
-
When
json.cache! cache_key, &block
is encountered in a template, Jbuilder emits a placeholder UUID key/value pair into the document (like"jbuilder-XXXX": null
) and moves on. It stores the (template digested) cache keys in a list of keys to be looked up, along with their corresponding UUID. -
After the template is rendered, the half-baked string is held in memory while JBuilder sends a
fetch_multi
for each of the keys in the set. -
For each key that is found in the cache, the corresponding UUID is blindly replaced with the value taken from the cache. In this case, a simple gsub for
"jbuilder-XXXX": null
, replacing it with whatever the cache has, like:"color": "red", "count": 2
-
For each key that is NOT found, execute the block with a fresh
json
object. Once completed, serialize thatjson
object to a string, and strip off the leading and trailing braces. Store that resulting string under the cache key and perform the substitution operation described in (3). The brace stripping must happen because thejson.cache!
call does not by default happen under a named key, and can be embedded in the a flow of a template, e.g.json.key1 'value1' json.cache! do json.key2 'value2' end
produces
{ "key1": "value1", "key2": "value2"}
Rendering
json.key2 'value2'
in isolation produces{"key2": "value2"}
, which we then strip of braces, which renders it fit to be inserted into the flow of other JSON objects.
Cons
-
This is a giant fucking hack.
-
Currently, the following case works fine in that only one entry is emitted:
json.key 'initial value' json.cache! do json.key 'new value' end
But under the proposal described, JBuilder will double-emit entries for
key
. By and large this will probably not matter - there's no real reason to do this, and most JSON parsers assume the latest definition takes precedence anyhow. -
Stuff starts to get tricky with nested partials/caches. It should all work fine in theory, there's just going to be a bookkeeping overhead.
...
Thoughts? @rwz, would love to know what you or @dhh think. If you're down, I can probably either build this or browbeat someone into doing it.