B3.3 · dive 1 — claim, the token mint
The oldest job, a server-clock lease, and token 1.
L1 fixes the machine's surface: claim, complete, retry, promote, reap join enqueue, browse, pending_size — five new verbs, every transition one script. L2 closes the happy path: claim hands out the oldest job with a server-clock lease and fencing token 1; complete with the right token retires the row — nothing remains. The script that opens every life is ten lines of Lua, and three design decisions live inside it.
Source: content/bcs3.3.md, quoting bcs_rung_3_3_check.out; the bundle is
committed at runtimes/elixir/lib/echo_mq/jobs.ex.
emq:{q}:<type> grammar — two at score
zero where lex order is mint order, two where the score carries a clock.The transcript
bcs_rung_3_3_check.out · verbatim · this dive reads L1 and L2L1 surface ok -- the machine's surface: claim, complete, retry, promote, reap join enqueue, browse, pending_size -- five new verbs, every transition one script L2 happy ok -- claim hands out the oldest job with a server-clock lease and fencing token 1; complete with the right token retires the row -- nothing remains L3 fence ok -- a stale token is refused on the wire: EMQSTALE; the lease holder's work survives the zombie's complete L4 schedule ok -- retry parks the job in the schedule, promote moves the due back to pending, and the next claim hands token 2 -- one job, two lives, one counter L5 dead ok -- attempts 2 against max 2 is the morgue: state dead, last_error kept, and the dead set browses in mint order like everything else L6 reap ok -- a 40 ms lease expires unanswered; reap returns the orphan to pending and the next claim holds token 2 -- crash recovery is one zset scan on the server's clock PASS 6/6
The keys, completing 3.1's map
content/bcs3.3.md · WhatFour sorted sets per queue, each earning its score semantics. pending stays
score-zero forever — lex order is mint order, the decision B3.2 ·
Jobs Are Entities recorded, honored here. active is scored by lease deadline, so the active set is
simultaneously the in-flight roster and the expiry index, and crash recovery is one range scan.
schedule is scored by run-at — exactly the separate set 3.2 pre-stated, so scores
never mix into the lex law. And dead is score-zero again, which means the morgue browses
newest-first like everything else in this series — the order theorem's third appearance on the bus.
The arithmetic is worth pausing on: two of the four sets carry no clock at all, because identity already carries one. Mint time is history inside the id, and where the machine needs a different clock — a lease deadline, a run-at — the score is where that clock lives. The two clocks never share a column.
Claim, the token mint
content/bcs3.3.md · What · HowThe claim script pops the lex-oldest pending id, increments attempts, stamps
the lease, and returns the job — quoted whole, because it is the contract:
local popped = redis.call('ZPOPMIN', KEYS[1])
if #popped == 0 then return {} end
local id = popped[1]
local jk = ARGV[1] .. id
local att = redis.call('HINCRBY', jk, 'attempts', 1)
redis.call('HSET', jk, 'state', 'active')
local t = redis.call('TIME')
local now = t[1] * 1000 + math.floor(t[2] / 1000)
redis.call('ZADD', KEYS[2], now + tonumber(ARGV[2]), id)
return {id, redis.call('HGET', jk, 'payload'), att}
Three design facts live here. The clock is the server's: TIME inside
the script means leases never see client skew, the engine's frozen-time rule keeps the reading stable for
the script's duration, and atomic execution guarantees the pop, the increment, and the lease land together
or not at all. The token is minted by HINCRBY — monotonic per job by construction,
which is precisely the property the fencing argument requires. And the job key is
constructed from a prefix argument — the bundle's one sanctioned exception to declared keys:
the id is unknown until popped, and 3.1's co-location law is what makes the construction safe — every key
the prefix can produce lives in the same slot as the declared ones, by grammar.
ZPOPMIN to the returned
triple — and watch the oldest job leave pending with state active, attempts 1,
and a lease scored on the server's clock.Static walk — 1) ZPOPMIN KEYS[1] pops the lex-oldest pending id
· 2) HINCRBY jk attempts 1 mints the token: attempts 0 becomes 1 · 3)
HSET jk state active · 4) TIME reads the server's clock, frozen for
the script's duration · 5) ZADD KEYS[2] now+lease id scores the active set by
lease deadline · 6) return {id, payload, att} — the consumer leaves holding
token 1.
The bundle lives inside runtimes/elixir/lib/echo_mq/jobs.ex — five
Script.new constants, SHA-pinned, dispatched EVALSHA-first through the appendix's loader,
surface gated at exactly the eight verbs. Size the lease above the worst legitimate work time and well
below your retry tolerance — the lease is a crash detector, not a deadline for excellence.
References
sources · relatedSources
- Valkey — Programmabilityatomic script execution — "all of the script's effects either have yet to happen or had already happened"; declared keys
- Kleppmann — How to do distributed lockingthe monotonic-token property the HINCRBY mint satisfies
- Valkey — Replicationtime frozen during a script, which makes TIME inside a write script sound; scripts replicate by effects
Related
- B3.3 — The State Machine in Luathe module hub; the full rung in context
- B3 — The Busthe chapter landing; Part III's arc
- B3.1 — The Fence and the Keyspacethe co-location law that sanctions the constructed key
- EchoMQ — the coursethe protocol in rung-level depth
- Redis Patterns Appliedthe substrate patterns under the bus
- Functional Programming in Elixirthe umbrella the runtimes live in