Class: MaquinaStream::ComponentCache
- Inherits:
-
Object
- Object
- MaquinaStream::ComponentCache
- Defined in:
- lib/maquina_stream/component_cache.rb
Overview
Caches pure render results: component partials, and whole sealed documents.
A component render is a pure function of its locals, and during a stream the same locals recur on every single frame: a code block that closed twenty frames ago is re-rendered, identically, twenty more times. Profiling a 20KB message put 56ms of a 68ms frame inside ActionView for exactly this reason — 36 fences at roughly 1.5ms each. Markdown parsing was 0.7ms of it.
Two tiers, because they solve different problems:
| Tier | What it buys |
|---|---|
| process-local | nanoseconds, and hits nearly always during one stream |
| store | survives a restart, a reload, and other workers. Optional |
The store tier is deliberately opt-in. Solid Cache is backed by the database, so a read is a query — worth it for a cold page reload, wasteful on a hot loop that the local tier already answers. Set it when a message is likely to be rendered by more than one process; leave it nil otherwise.
MaquinaStream::ComponentCache.store = Rails.cache
Caching does nothing for bandwidth. It is a CPU fix only.
Constant Summary collapse
- MAX_ENTRIES =
How many entries the process-local tier holds before evicting the least recently used. A cap, not a target: the working set of one stream is far smaller.
1_024- NAMESPACE =
Key prefix for the store tier. Versioned, so a change to what is cached invalidates the old entries rather than deserializing them.
"ms:component:v1"
Class Attribute Summary collapse
-
.store ⇒ Object
The optional second-tier cache store — anything answering
read(key)andwrite(key, value),Rails.cachein practice.
Class Method Summary collapse
-
.clear! ⇒ Object
Empties the process-local tier.
-
.fetch(*key_parts) ⇒ Object
Returns the cached value for
key_parts, calling the block to compute it on a miss. -
.reset_stats! ⇒ Object
Zeroes the hit and miss counters.
-
.size ⇒ Object
How many entries the process-local tier holds, capped at MAX_ENTRIES.
-
.stats ⇒ Object
Hit rate is worth being able to see: a cache that never hits is worse than no cache, and a cache that always hits on a changing document is a key that is not capturing what it should.
Class Attribute Details
.store ⇒ Object
The optional second-tier cache store — anything answering read(key)
and write(key, value), Rails.cache in practice. Nil by default, and
deliberately so: see the note above.
45 46 47 |
# File 'lib/maquina_stream/component_cache.rb', line 45 def store @store end |
Class Method Details
.clear! ⇒ Object
Empties the process-local tier. Does not touch #store.
61 62 63 |
# File 'lib/maquina_stream/component_cache.rb', line 61 def clear! mutex.synchronize { entries.clear } end |
.fetch(*key_parts) ⇒ Object
Returns the cached value for key_parts, calling the block to compute
it on a miss. The key is the digest of the parts joined, so they must
cover everything the block's result depends on.
50 51 52 53 54 55 56 57 58 |
# File 'lib/maquina_stream/component_cache.rb', line 50 def fetch(*key_parts) key = digest(key_parts) local(key) || from_store(key) || begin value = yield write(key, value) value end end |
.reset_stats! ⇒ Object
Zeroes the hit and miss counters.
76 77 78 |
# File 'lib/maquina_stream/component_cache.rb', line 76 def reset_stats! @stats = {hits: 0, misses: 0} end |
.size ⇒ Object
How many entries the process-local tier holds, capped at MAX_ENTRIES.
66 |
# File 'lib/maquina_stream/component_cache.rb', line 66 def size = entries.size |
.stats ⇒ Object
Hit rate is worth being able to see: a cache that never hits is worse than no cache, and a cache that always hits on a changing document is a key that is not capturing what it should.
71 72 73 |
# File 'lib/maquina_stream/component_cache.rb', line 71 def stats @stats ||= {hits: 0, misses: 0} end |