jonnify·redis /redis-patterns/overview/redis-under-portal/two-roles

R0.2.2 · Valkey under the Exchange Platform — dive 2

The two roles.

One store, two jobs below the facade: EchoCache, the near-cache in front of the read path — derived state, a copy of the truth, safe to drop — and the EchoMQ bus, the work itself — authoritative state, built for atomic hand-off and recovery.

Grounding: content/bcs4.md + bcs4.1.md (the EchoCache role) · bcs3.2.md + bcs3.3.md (the EchoMQ bus role) — every figure verbatim from a committed record.

Inspect a role. Pick one — by button or by hovering its box; the readout answers with its state kind, its shapes, and its committed figures.
the Exchange Platform EchoCache · the near-cache L1 ETS over L2 Valkey · derived state a copy of the truth — safe to drop the EchoMQ bus pending · active · schedule · dead authoritative state — the jobs are the work Valkey · the engine
readout · Pick a role. One store, two kinds of state — the derived near-cache and the authoritative bus, both below the facade.

Static verdicts — EchoCache → derived, L1 hits at 762 ns against 31 us per L2 GET (bcs4.1) · the EchoMQ bus → authoritative, the three-field row and the four sorted sets (bcs3.2, bcs3.3) · Valkey → external, one engine under both.

§1

The cache machine is EchoCache

content/bcs4.md · bcs4.1.md

The first role is the near-cache in front of the engine’s reads: an L1 of declared ETS tables over the L2 Valkey the systems already share. Its one-line case is the bcs4 title made plain — branded keys, local speed, bus-driven coherence. A warm read is a local ETS lookup; a cold read fills through a declared loader and lands the L2 row with its TTL; an L1 drop falls back to L2 before the loader is consulted again.

The state here is derived — a copy of a truth that lives elsewhere, so a dropped cache costs a slower read, never a lost fact. And the speed difference is committed, not estimated:

content/bcs4.1.md · the headline, committed · verbatimfrozen
1311621 hit reads per second (762 ns each) against 31 us per L2 GET on the same
wire -- the L1 hit is 40 times cheaper than the round trip it replaces, inside the derived band

This role grounds the caching and data-modeling families — in EchoCache’s committed record, or in clean standalone examples.

§2

The EchoMQ bus holds the work

content/bcs3.2.md · bcs3.3.md

The second role is the bus: the owned-protocol job queue at echo/apps/echo_mq, backed by Valkey. Here the store holds the queues themselves, and the state is authoritative: the jobs in the sets are the work, so the bus is built for atomic hand-off and recovery, not for eviction. The shapes are exact. A job row is a hash of exactly three fields — state, attempts, payload — and deliberately nothing more: no enqueued_at, because mint time already lives inside the id. Per queue, four sorted sets carry the lifecycle:

emq:{q}:pending    # score-zero forever — lex order is mint order: FIFO, browse, and time range in one set
emq:{q}:active     # scored by lease deadline — the in-flight roster and the expiry index at once
emq:{q}:schedule   # scored by run-at — the separate set that keeps scores out of the lex law
emq:{q}:dead       # score-zero again — the morgue browses newest-first like everything else

Eight verbs over six scripts move work between them. The order theorem’s dividend is committed, not asserted:

content/bcs3.2.md · J4, the dividend on stage · verbatimfrozen
the last five minted in reverse mint order; the very first job sits at the head;
301 pending, no second index anywhere

Notes on ValkeyIn a sorted set, elements with the same score are ordered lexicographically — the engine fact behind the score-zero pending set, and the reason delayed work lives in a separate run-at-scored set — valkey.io/topics/sorted-sets.

This role grounds the queues, coordination, streams, and flow-control families.

§3

Which family, which role

the course map · bcs3 · bcs4

The split is the map for the whole course: a pattern family grounds in one role or the other. Pick a family to read which role carries it and what it holds there.

Map a family to its role. Pick a family — by button or by hovering its box; its role lights with it, and the readout names what it holds.
caching data modeling queues coordination streams & events flow control EchoCachethe derived half · read path the EchoMQ busthe authoritative half · work path
readout · Pick a family. The caching and modeling families ground in EchoCache; the queues, coordination, streams, and flow families ground in the bus.

Static verdicts — caching, data modeling → EchoCache (derived) · queues, coordination, streams & events, flow control → the EchoMQ bus (authoritative).

the application · one engine, two keyspaces

Each role writes its own prefix

The bus writes the closed emq:{q}:<type> grammar; EchoCache’s keyspace is its own — a fresh prefix beside emq:, never inside it, hashtagged on the table name for the clustered day. On Valkey, each L2 row carries its TTL on the server’s own clock.

content/bcs4.1.md · the cache’s keyspace and the L2 clock · verbatim figuresfrozen
ecc:{<table>}:<id>   ← a fresh prefix beside emq:, never inside it
PTTL 300 ms of 300    ← the L2 row, written with SET ... PX
the split

One store can hold two kinds of state: a derived cache, safe to drop, and an authoritative queue, the work itself. The kind of state determines how the role is built.

its BCS application

EchoCache holds the derived half — declared tables, single-flight fills, jittered TTL. The EchoMQ bus holds the authoritative half — the three-field row, the four sorted sets, every transition one atomic script.

Two roles, two kinds of state, two halves of the catalog. Which role grounds a pattern is the first thing each chapter names — and the next dive opens the bus’s own story: the tier that stopped being a reservation.

§4

References

sources · related

Sources

Related in this course