Skip to content

Proposal for caching improvements #289

Open
@vincentwoo

Description

@vincentwoo

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

  1. 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.

  2. 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.

  3. 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

  4. For each key that is NOT found, execute the block with a fresh json object. Once completed, serialize that json 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 the json.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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions