Module C4.08
Branded ids & persistence
C4.07 built the id. This module stores it — and the id earns its keep as the key.
A branded id is a 14-character string: a three-letter namespace and an eleven-character Base62
snowflake. It is compact, opaque, and — the property this module turns on —
lexicographically sortable. Because the Base62 alphabet runs in ascending code-point order and
the snowflake carries the timestamp in its high bits, the string sorts exactly as the integer does: byte order
is mint order. So a Set<string> of ids, or a Map<string, _>
keyed on them, is already time-ordered — no created_at column, no second index. The same
id is a bigint primary key in SQLite and PostgreSQL and a namespaced string key in
Redis and Valkey. This module re-derives the Elixir course's F4.08
in F#, grounded in the real echo_fs EchoMQ port, across three dives.
The key, the row, and the port
Persistence asks three questions, and this module answers them in order. What is the key? A branded id, composed into a per-queue key. What is stored under it? A row — a flat, store-neutral record whose payload is an opaque string. Where does it live? Behind a port: one surface, two backings, so the durable store can change without the caller changing.
The EchoMQ bus uses exactly this shape. Its keyspace is emq:{q}:<type>; its rows
are a Map keyed by branded id; its store today is in memory, with a Valkey transport
named and on the way. Each dive grounds in the real F# port (echo_fs/EchoMQ/) and
cross-links its Elixir F4.08 sibling, with a note on the F# implementation and its cost.
The keyspace builder · pick a queue and an id
Choose a queue and a branded id; the builder composes the row key
emq:{q}:job:<id> and computes its cluster slot — CRC16-XMODEM of the hashtag,
modulo 16384. Every key of one queue shares the {q} hashtag, so they all land on
one slot. The readout names each part.
The branded id is the key, the row is what it addresses, and the hashtag fixes which slot the row lives in. One id; three jobs, all done before any store is opened.
The three dives
Read them in order. Each stands on valid F# verified in dotnet fsi and quotes the
real echo_fs port, and each cross-links the matching Elixir F4.08 dive with a note
on the F# cost model. The thread: build the key, store the row, and put the store behind a port.
Keys & rows
The branded id composes into the row key emq:{q}:job:<id>; the row is the persisted entity; the hashtag pins the slot.
- the keycompose, gate, and hash the key from the id
Serialization
The payload as a string; the branded id as a stable, sortable key across SQLite, PostgreSQL, and Redis — the parity point.
- the rowwhat is stored, and why byte order is mint order
The store port
One enqueue / claim / complete surface; the in-memory store today, the Valkey backing next.
- the portthe durable backing swaps in with no caller change
EchoMQ in F#
Status — echo_fs is an in-memory model. The EchoMQ protocol — the Lua transitions executing on a Valkey wire — is not implemented (there is no Lua and no Valkey client in the code); that is the coming-soon transport (EchoMQ.Connector). This block shows how the model uses the structure, not a running bus.
Every C4 dive carries this block: how the bus uses the structure, grounded in the real
echo_fs port (the F# skeleton of echo/apps/echo_mq). For
persistence, the bus is the worked example end to end — the key, the row, and the port are exactly what this
module teaches.
echo_fs · the keyspace, the rows, and the swappable store
The keyspace is EchoMQ.Keyspace: queueKey queue keyType
composes "emq:{" + queue + "}:" + keyType, and jobKey gates a
valid branded id before composing emq:{q}:job:<id>. The cluster slot is
slot — CRC16-XMODEM of the hashtag, modulo 16384 — with the published vector
slot "123456789" = 12739.
The persisted state is EchoMQ.Store.QueueState: the rows
(Map<string, Job> keyed by branded id) plus the four sets —
Pending, Schedule, Active,
Dead. The public verbs live in EchoMQ.Jobs, each delegating to
a pure Store transition.
The in-memory Store persists state today; the Valkey transport
EchoMQ.Connector lands next — its eval currently raises
failwith "EchoMQ Valkey connector: coming soon", behind the same surface, so the
durable backing swaps in with no caller change.
C4.07 · the id
A namespaced, time-ordered, Base62-encoded id that decodes to a moment.
C4.08 · the key and the store
Composed into a row key, stored as a sortable map key, behind a port whose backing can change.
References
Sources
- Microsoft — F# documentation — records,
Map, andSetfor keyed, ordered state. - FSharp.Core API reference —
MapandSet, the persistent collections keyed on the id. - Microsoft — .NET documentation —
System.Text.Encodingand the bit operators the slot uses. - The F# Software Foundation — F# on the .NET runtime, the home of
echo_fs.
Related in this course
- Elixir F4.08 — Branded ids & persistence — the module this one re-derives in F#.
- C4 — Algorithms & Data Structures — the chapter this module sits in.
- C4.08.1 — Keys & rows — the first dive.
- C1 — F# Language — records,
Map, andSetin depth.