jonnifyredis

R3.04.1 · dive 1

States as locations

The value the lifecycle updates is not a status field. It is the Redis key the job id lives in — and a transition moves the id to the next key.

A naive queue stores a status column and updates it as the job moves, so the location and the status can disagree after a crash. EchoMQ holds no status field: emq:{queue}:wait and :active are LISTs, :delayed, :prioritized, :completed and :failed are ZSETs, and the state is the key the id sits in. Fire a transition on the right and watch the id hop from one key to the next.

States as locations · the job id hops from one key to the next

type emq:{queue}:wait LIST job 42 emq:{queue}:active LIST emq:{queue}:delayed ZSET emq:{queue}:prioritized ZSET emq:{queue}:completed ZSET emq:{queue}:failed ZSET

The state is the location

The atomic-updates pattern names the thing being updated as a value at a key. Applied to a queue, that value is the job's place. A naive queue stores a status field on the job record — "wait", "active", "done" — and updates it as the job moves. Two facts can then disagree: where the job actually sits, and what its status claims. A crash between writing the status and moving the job leaves the pair out of sync, with nothing to reconcile them.

EchoMQ holds no status field. A job's state is the Redis key its id lives in. There is no separate column to fall out of sync, because the location is the state.

A job's state is not a field that can lie about where the job is — the state is the key the id lives in, so the location can never disagree with itself.

The five locations

A job id lives in exactly one place at a time, and the structure type carries meaning. The wait and active states are LISTs; delayed, prioritized, completed and failed are sorted sets scored by time or priority:

# a job's state is the key its id lives in — no status column
emq:{queue}:wait         → LIST  · ids waiting to run
emq:{queue}:active       → LIST  · ids in flight under a lock
emq:{queue}:delayed      → ZSET  · scored by when the job is due
emq:{queue}:prioritized  → ZSET  · scored by priority
emq:{queue}:completed    → ZSET  · finished ids, scored by finish time
emq:{queue}:failed       → ZSET  · failed ids

EchoMQ.Keys builds each from the queue context — wait/1, active/1, delayed/1, prioritized/1, completed/1, failed/1. The {queue} here is the queue-name placeholder the key builder fills in (EchoMQ.Keys.base/1), the documentation form the shipped queue dives use.

wait / active
LISTs. A job is pushed onto wait and moved into active to run; the active list is the in-flight set under a lock.
delayed / prioritized
ZSETs. The score is the due time (delayed) or the priority (prioritized), so the queue can pop the next-due or highest-priority id.
completed / failed
ZSETs of terminal ids, scored by finish time, so old entries can be trimmed by age or count.

LIST membership means waiting or in flight; ZSET membership means scheduled or terminal — the structure type is part of what the state means.

A transition moves the id

A transition is moving the id from one key to the next, plus an update to the job hash emq:{queue}:<id>. Enqueue pushes the id onto wait. Pick up moves it from wait into active. Finish moves it from active into completed. Fail moves it from active into failed. The id is in exactly one structure at every instant — and which structure it is in is the job's state.

Because the state is the location and a transition is a move across structures, the move must be atomic. A move that removes the id from one key and adds it to another in two separate commands has a window where the id is in neither, or in both. That is why the whole transition runs as one Lua script — moveToFinished-14.lua, one EVALSHA over the fourteen keys that name every location at once. Pick a transition below and watch which structure the id leaves and which it enters.

One transition · which structure the id leaves, which it enters

emq:{queue}:wait LIST · job 42 leaves RPOPLPUSH emq:{queue}:active LIST · job 42 enters pick up · the id leaves the wait list and enters the active list
the pattern

The value being updated is a location, not a status field, so the location can never disagree with the state. A transition is an atomic move of the id from one structure to the next.

in EchoMQ

The locations are EchoMQ.Keys.wait/active/delayed/prioritized/completed/failed, the job hash is EchoMQ.Keys.job/2, and a transition moves the id between them in one moveToFinished-14.lua step.

A transition removes the id from one structure and adds it to another in one atomic move, so the id is in exactly one location at every instant.

In EchoMQ — the location is the state

EchoMQ's queue holds no status column. The EchoMQ.Keys module builds every location from the queue context, and a job's state is read off which key its id sits in. A transition is an atomic move across structures — the same moveToFinished-14.lua that the next dive opens. No status field means there is no second fact to fall out of sync with where the job actually is.

Door · not depth The full key taxonomy and the include graph that names every structure a transition touches are E6 · the lifecycle in the dedicated EchoMQ course. This dive teaches that a state is a location; that course teaches the whole key map and the moves over it.

References

The Redis structures a job id lives in — the lists, the sorted sets, the job hash — and the queue protocol whose location model EchoMQ ports.

Sources

Related in this course