R1.07 · Caching — the chapter workshop
Cache the emoji set.
The chapter capstone: take the six patterns and put EchoStore in front of one real consumer
read — codemojex’s emoji set, the reference data Codemojex.Guesses.submit/3
checks every guess against.
Grounding: echo/apps/echo_store (EchoStore.Table, Coherence) · echo/apps/codemojex (Codemojex.Guesses, Codemojex.Cache) · bcs.4.md — every figure verbatim from a committed record.
Static verdicts — 1 cache → fetch/3 (:hit | :l2 | :fill) ·
2 consistent → broadcast/enqueue + newer? · 3 harden
→ single-flight + jittered TTL · 4 measure → stats/1 counters.
The consumer, and the read path in layers
codemojex/game.ex · echo_store/table.excodemojex validates every guess against the round’s emoji set.
Codemojex.Guesses.submit/3 turns an untrusted guess into a branded JOB on the
player’s lane or one closed error, and one of the first checks is the keyboard: it calls
Codemojex.Cache.fetch_set(set_id) and runs EmojiSet.valid_guess?/2, answering
{:error, :bad_guess} for a code the round’s keyboard does not expose. That emoji set
lookup is reference data — read on every guess, immutable for the round’s life
— which is exactly the read-heavy, write-light shape cache-aside is built for. Fronting it with
EchoStore.Table is the workshop.
The read path stacks four layers, each adding one move taught earlier in the chapter, and each leaving
the read correct on its own. The base layer is a cache-aside read:
EchoStore.Table.fetch/3 checks L1 ETS, then on a miss runs a single-flight fill —
GET ecc:{cm_emojisets}:<id>, the loader, then SET … PX — and
returns {:ok, value, source} with source :hit | :l2 | :fill. The next layer keeps
the cache consistent: a room’s emoji set changing runs Coherence.broadcast/4
on the fast lane or Coherence.enqueue/5 on the at-least-once job lane, and
Coherence.newer?/2 resolves a late message newer-wins.
The third layer hardens the set every guess touches — EchoStore does this
by construction: the single-flight flights map coalesces a herd onto one fill, and a jittered
TTL (ttl ± ttl·jitter) keeps a cohort from expiring together. The fourth layer
measures: EchoStore.Table.stats/1 returns the counter snapshot —
hits, misses, fills, l2_hits, coalesced, swept, full_skips, sweeps, coh_applied, coh_stale plus
live size — so the hit rate is a number, not a guess. Nothing here is new: each layer is
a pattern from R1.01–R1.06, applied to one real surface. The work is the assembly.
The emoji-set read path is cache-aside at the base, with three layers stacked on top: keep it consistent on a change, let the single-flight and jitter absorb a herd, and read the hit rate off the counters. Each layer is one move from earlier in the chapter.
The three stages
cache → consistent → harden & measureThe workshop is three dives. Each takes one layer and builds it on the real consumer surface, ending with the read path one step closer to production. Take them in order: the cache must exist before it can be kept consistent, and it must be consistent before its hit rate means anything.
Cache the catalog
Wire EchoStore.Table.fetch/3 over the emoji set: an L1 ETS hit, else a
single-flight fill — GET ecc:{cm_emojisets}:<id> → loader →
SET … PX. The base read path.
Keep it consistent
When a room’s emoji set changes, drop the L1 row and resolve newer-wins:
Coherence.broadcast/4 (fast) or Coherence.enqueue/5 (the job lane), with
newer?/2 the comparison. Choose the lane.
Harden and measure
The single-flight flights map and the jittered TTL absorb a herd by
construction, and EchoStore.Table.stats/1 reads the hit rate off the counters.
Walk the build
echo_store/table.ex · coherence.exPick a stage to see which EchoStore surface it adds to the read path and what the cache can
do once it lands. The surface grows as the stages stack; the readout names the new calls and the property
the layer secures.
Cache-aside at the base, coherence on a change, the single-flight and jitter under a herd, and counters reporting the hit rate — four moves layered into one read path, each correct on its own.
EchoStore.Table in front of codemojex’s emoji set:
fetch fills on a miss, broadcast/enqueue keep it consistent, the
jittered TTL and single-flight absorb a herd, and stats reports the hit rate.
Three stages, four layers, one read path. The workshop turns the chapter’s patterns into a real consumer’s catalog cache — cached, consistent, hardened, and measured.
EchoStore against live Valkey
The figures the workshop reproduces are committed, from the EchoStore gate against the live engine — the L1 hit cost and the lane prices, figure by figure.
L1 ETS hit 1311621 reads/s ← 762 ns each L2 GET 31 us ← the L1 hit is 40 times cheaper coherence · broadcast lane 72 us ← fire-and-forget, at-most-once coherence · job lane 148 us ← at-least-once: 2.1 times the latency
Notes on ValkeyEvery L2 fill is SET … PX —
value and expiry in one atomic command — so the second layer expires itself even if every node forgets;
a separate EXPIRE would leave an immortal key if the process died between the two
— valkey.io/commands/set.
EchoStore, the near-cache in depth
The two-layer read path and the coherence this workshop builds are walked rung by rung in the Cache pillar — EchoStore’s cache-aside over L1 ETS and L2 Valkey, kept coherent by mint-time version.
/bcs · Part IVThe EchoStore manuscript
L1 ETS over L2 Valkey, coherence by mint time, the lane that remembers — the cache built and gated, chapter by chapter.
start hereR1.07.1 · Cache the catalog
The base read path: fetch/3 over the emoji set, an L1 hit or a single-flight
fill.
References
sources · relatedSources
- Valkey — SET —
SET … PXsets a value and its expiry in one atomic command; the L2 fill of every cache layer. - Valkey — Topics — the engine the EchoStore gate is measured against, Valkey.
- Redis — Documentation — strings, expiry, and counters — the command families the read path is built from.
- Sanfilippo, S. — antirez weblog — the Redis creator on expiry, atomic operations, and treating cached values as a disposable copy.
- Answer.AI — The /llms.txt convention — the machine-readable map convention this course follows for agent readers.
Related in this course
- R1.07.1 · Cache the catalogthe base read path
- R1.07.2 · Keep it consistentcoherence and the lane choice
- R1.07.3 · Harden and measuresingle-flight, jitter, the counters
- R1.01 · Cache-asidethe base pattern
- R1.02 · Write-throughthe consistency-first alternative
- R1 · Cachingthe chapter