jonnifyfsharp

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.

row key · emq:{q}:job:<id> emq: literal {email} hashtag · pins the slot job: family JOB0Dqhu1EacDY branded id · the key CRC16(hashtag) mod 16384 slot 10780

      

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.

live module hub built dive ready soon specified

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

Related in this course