jonnify·bcs /bcs/bus/jobs-are-entities/enqueue-one-script

B3.2 · dive 2 — enqueue, one script

Policy before existence before write.

The whole admission law is ten lines of Lua, and the ordering of its three acts is a decision: an invalid id is refused before it can half-exist, a duplicate is answered before anything is touched, and the row and the pending entry land in one atomic step or not at all.

Source: content/bcs3.2.md, quoting bcs_rung_3_2_check.out; the script travels inside runtimes/elixir/lib/echo_mq/jobs.ex, SHA-pinned by Script.new.

The admission, simulated. Three fixed presentations stepped through the script's three acts — a minted JOB id (demonstration data), the same id again, and the committed ORD0Nt6z93U3dY in the job position. The kind check is performed live.
act 1 · policy string.sub(ARGV[1], 1, 3) ~= 'JOB' refuse kinds first act 2 · existence EXISTS KEYS[1] == 1 answer duplicates second act 3 · write HSET row · ZADD pending 0 mutate last, atomically
readout · Present a candidate. The model runs the committed script's three acts in order and reports where each presentation resolves — and what the caller receives.

Static verdicts — first call → 1 on the wire, {:ok, :enqueued} at the caller · the same id again → 0, {:ok, :duplicate}, nothing touched · ORD0Nt6z93U3dY → EMQKIND job id must be JOB-namespaced, refused at act one, before existence is even asked.

§1

The transcript

bcs_rung_3_2_check.out · verbatim · this dive reads J2 and J3
content/echo_data/runtimes/elixir/bcs_rung_3_2_check.out · verbatimfrozen
boot: the registry grows by one -- JOB, work as a kind with identity and lifecycle
J1 surface ok -- the bus module's surface: enqueue, browse, pending_size -- scripts and key shapes are nobody's business
J2 idempotent ok -- enqueue is one script and idempotent by id: first call enqueued, second answered duplicate, the row untouched and pending holds 1
J3 kind ok -- kind policy lives in the script: an ORD id in the job position answers EMQKIND on the wire -- the key let it pass, the law did not
J4 dividend ok -- the order theorem's dividend: newest-first browse over the ids themselves returns the last five minted in reverse mint order; the very first job sits at the head; 301 pending, no second index anywhere
J5 cargo ok -- the cargo law holds: the payload carries ORD0Nt6z93U3dY and a quantity, never a row -- decoded and re-parsed on the far side of the wire
PASS 5/5
§2

The script

content/bcs3.2.md · What

The whole admission law, verbatim from the chapter — ten lines, three acts:

if string.sub(ARGV[1], 1, 3) ~= 'JOB' then
  return redis.error_reply('EMQKIND job id must be JOB-namespaced')
end
if redis.call('EXISTS', KEYS[1]) == 1 then
  return 0
end
redis.call('HSET', KEYS[1], 'state', 'pending', 'attempts', '0', 'payload', ARGV[2])
redis.call('ZADD', KEYS[2], 0, ARGV[1])
return 1

"Policy before existence before write: an invalid id is refused before it can half-exist, a duplicate is answered before anything is touched, and the row and the pending entry land in one atomic step or not at all. Both keys live in one queue's family, so the script is single-slot legal by 3.1's grammar without a thought spent." The act order is normative for every bundle script to come: refuse kinds first, answer duplicates second, mutate last.

J2 gates the duplicate path as a success shape: first call enqueued, second answered duplicate, the row untouched and pending holds 1. At-least-once producers retry; the bus answers calmly and changes nothing — duplicate is the normal vocabulary of a healthy producer, not a defect signal.

§3

The wire class, discovered live

content/bcs3.2.md · What

The rung's first run failed J3 on a real wire fact: the engine wraps class-less custom errors in its generic ERR prefix, and the connector's eval path surfaces server errors as {:error, {:server, msg}}. The fix was better protocol citizenship, not a looser match — the refusal now carries its own error class as its first word, EMQKIND, exactly the way the boot fence types its refusal, and the committed line reads an ORD id in the job position answers EMQKIND on the wire -- the key let it pass, the law did not. That last clause is 3.1's division performing: wellformedness at the key, policy at the script, each refusing in its own voice.

The decision generalizes: refusals carry their own wire class — every typed refusal a bundle script issues leads with its class word, never riding the generic ERR.

§4

The client half

content/bcs3.2.md · How (Elixir · Go)

The Lua is the implementation; the client half is a pattern match on the typed classes, verbatim from the chapter:

case Connector.eval(conn, @enqueue, keys, [job_id, payload]) do
  {:ok, 1} -> {:ok, :enqueued}
  {:ok, 0} -> {:ok, :duplicate}
  {:error, {:server, "EMQKIND" <> _}} -> {:error, :kind}
  other -> other
end

The cross-runtime note from the chapter's How: the script is the contract — the same source string yields the same SHA1, and any client on any runtime that loads it speaks identical semantics. The Go consumer embeds the same bytes, computes the same digest, and gets the same three answers.

The wire answers, matched. Four server replies traced to the clause that takes them — the typed classes the connector surfaces, and the one failure mode the class word exists to prevent.
readout · Select a server reply. The match runs top to bottom; the readout names the clause that takes it and the answer the caller receives.

Static record — 1 → {:ok, :enqueued} · 0 → {:ok, :duplicate} · a reply leading with EMQKIND → {:error, :kind} · a class-less error riding the generic ERR → falls through to other — the first run's J3 failure mode, the reason the class word exists.

§5

References

sources · related

Sources

  • Valkey — Sorted setsthe same-score lexicographic family the script's ZADD-at-zero feeds
  • Valkey — ZRANGEthe REV and BYLEX forms the pending set answers; equal-score elements order lexicographically

Related