E2.01 · Movement I · The Core
The lifecycle &
the state machine
A job is always in exactly one of eight states, and every move between them is one atomic Lua script.
A job in EchoMQ occupies one of eight states at a time —
wait, paused, delayed,
prioritized, active, completed,
failed, waiting-children — and each is one Redis key built by one
function in EchoMQ.Keys. Every move between states is one atomic Lua
script: moveToActive-11 picks a job up and takes the lock,
moveToFinished-14 completes it, moveToDelayed-8 retries it, and
moveStalledJobsToWait-8 recovers a stalled one. When a script cannot complete it returns a
negative integer from a closed -1…-11 set. The core is shipped, so
every surface below is read from the real source. Three dives follow.
Movement I · Core (as-built) ← redis-patterns R3
Step a job through the machine
The state machine is easiest to read by walking it. Step a captured job along two real paths and read the
transition script named at each edge. The happy path is
add → wait → active → completed; the retry path is
add → wait → active → failed-handling → delayed → wait → active. Each move names exactly
one Lua script, and the lifecycle never lets a job be half-moved — every transition is one atomic step.
A captured job's path · pick a path, then step
A job is always in exactly one state, and each move is one named atomic Lua script. The state and the script are the protocol — the same in Elixir, Go, and Node.js.
The dives
Three dives build the module — the states first, then the script behind each transition, then the lock that keeps a job owned.
The eight states
wait · paused · delayed · prioritized · active · completed · failed · waiting-children — each with its Redis location, type, key function, and terminal-or-not.
Every transition & its script
The script behind each move — moveToActive-11, moveToFinished-14, moveToDelayed-8, moveStalledJobsToWait-8 — its KEYS arity, the atomic step list, and the closed -1…-11 codes.
The lock protocol
The SET …:lock uuid PX acquire inside moveToActive, the extendLock-2 heartbeat, the token verification that returns -2/-6, and the 30000/15000/30000ms timing.
How it fits
The lifecycle stands on the two immutable layers E1 froze — the L1 state keys and the L2 transition scripts —
and sets them in motion. One transition makes the layering concrete: a worker picks up the next job, and at
L4 it calls a runtime API; at L3 the executor dispatches a script by SHA
(EchoMQ.Scripts.move_to_active/4); at L2 the script
moveToActive-11 runs atomically; at L1 it moves a job id from
emq:{queue}:wait to emq:{queue}:active and sets the lock at
emq:{queue}:{jobId}:lock with a UUID token and a PX TTL. The
completion script moveToFinished-14 first verifies that token; a missing or mismatched
lock returns -2 or -6 from the closed set. L1 and L2 are
byte-identical across runtimes; only L3 and L4 differ — the Golden Rule.
The state keys (EchoMQ.Keys.wait/1, active/1, …) and the
transition scripts (moveToActive-11, moveToFinished-14) —
frozen, with the same closed -1…-11 codes in every runtime.
Elixir dispatches the moves with EchoMQ.Scripts over a Redix pool and renews locks
with one EchoMQ.LockManager timer per worker; Go and Node.js drive the same scripts
their own way. The wire underneath does not move.
The Golden Rule: L1 and L2 are immutable and shared; L3 and L4 vary. The eight states and the four transition scripts are the protocol — the same in every runtime; the executor that dispatches them is each runtime's own.
Start with the eight states, then read every transition and its script, then the lock protocol. The chapter closes with a workshop that runs a job through every state — reachable from E2 · the core.
References
Sources
- BullMQ — Documentation — the wire protocol EchoMQ implements: the eight states, the transition scripts, and the lock protocol.
- Redis — RPOPLPUSH — the reliable wait→active move at the heart of
moveToActive. - Redis — LPUSH — the push onto the
activelist a pickup performs. - Redis — Sorted sets — the ZSET scoring behind delayed, prioritized, and the terminal sets.
Related in this course
- E2 · The core — the chapter landing.
- E1.03 · The Lua script layer — the scripts these transitions run.
- E1 · The protocol — the immutable wire this chapter sets in motion.
- redis-patterns R3 · Reliable queues — the pattern this chapter deepens.