E2.04 · Movement I · The Core
The three runtimes
& interop
One wire, three runtimes — the reference, the port, and the origin — and a job round-trips between any two that share it.
EchoMQ's v1 line speaks the BullMQ wire — the emq:
keyspace, meta.version = bullmq:5.65.1, the same 50 Lua scripts
— and three runtimes share it: the Elixir reference (echo/apps/echomq
v1.3.0), the Go port (apps/echomq-go, partial
with named gaps), and Node.js, which is the BullMQ reference implementation itself —
EchoMQ has no first-party Node runtime today. The Golden Rule holds across all three: L1 (the
keyspace and field names) and L2 (the scripts) are byte-identical; only L3 (the executor) and L4 (the client API)
vary. Three dives follow, and the chapter's place in the 2.0 fork closes the page.
Movement I · Core (as-built) ← redis-patterns R3
The runtime-status explorer
The three runtimes are not equal in maturity, and a depth course says so. Pick a runtime to read its source, its role, and its honest v1-line status — the reference, the partial port with its named gaps, and the origin that has no first-party EchoMQ runtime. Every status below is read from the real trees.
The v1 line · pick a runtime to read its status
Three runtimes, one wire. The reference is Elixir, the port is Go (honestly partial), and the origin is Node — and a job round-trips between any two that speak the same wire.
The dives
Three dives build the module — the reference runtime's OTP shape first, then the Go port's honest gaps, then the interop that ties the fleet together and the v2 trajectory ahead of it.
The Elixir architecture
The reference runtime's L3/L4 — library-only and host-supervised, one BEAM process per job via Task.async, the one-timer LockManager, the NimblePool connection, and EVALSHA dispatch.
The Go gaps
The honest port status — the non-atomic add path (two commands where the reference runs one atomic script), the attemptsMade-vs-atm tag nuance (L4, not a wire bug), and the cluster validator Go does carry.
Cross-runtime interop
v1 interop today — one job hash, shared scripts, the atm round-trip Elixir ⇄ Go — and the fleet's v2 trajectory: the fork, the proposed echomq-node, and Dragonfly as the first-class substrate.
How it fits
A runtime is free to drive the protocol however its host language drives best — OTP processes in Elixir,
goroutines in Go, an event loop in Node — but every runtime writes the same keys and runs the same scripts. The
emq: keyspace and the field names are L1; the 50 Lua scripts every
transition runs are L2; both are byte-identical across runtimes. The executor above them is
L3 and the client API is L4 — each runtime's own. That is why a job enqueued by
one runtime can be processed by another: the wire underneath does not move. The course's honest cross-runtime
status — Elixir reference, Go partial, no first-party Node — is the truth this module teaches.
The emq: keyspace, the field names, and the 50 Lua scripts every transition runs —
frozen and shared, the same in every runtime.
Elixir drives the wire with supervised OTP processes; the Go port drives the same scripts with goroutines (with the named gaps); Node is the upstream reference. The wire does not move; the executor above it does.
The Golden Rule for runtimes: L1 and L2 are immutable and shared; L3 and L4 vary. The reference is Elixir, the port is Go, the origin is Node — and the wire is the same in every one.
Start with the Elixir architecture, then the Go gaps, then cross-runtime interop. This module follows E2.03 · lock management and E2.02 · jobs, queues & workers — reachable from E2 · the core.
The 2.0 fork — EchoMQ leaves the BullMQ wire
The shared wire above is the v1 line (frozen at 1.3.0) — the BullMQ wire.
emq.1 ships EchoMQ 2.0, which leaves it: the
emq: keyspace replaces emq:, every Lua key is declared in
KEYS[], the per-queue {q} hashtag is applied transparently by
the core, and meta.version becomes echomq:2.0.0. Interop then
becomes the EchoMQ fleet's own — stock BullMQ clients cannot speak v2 by design, the Go port must implement 2.0
to stay in the fleet, and a first-party echomq-node is proposed (it does not exist) — and the payoff is
Dragonfly-native multithreading.
References
Sources
- BullMQ — Documentation — the wire protocol, the lifecycle, and the Lua scripts the three runtimes share.
- Redis — EVALSHA — the cached-script dispatch the Elixir reference uses.
- DragonflyDB — Running BullMQ on Dragonfly — the thread-per-shard substrate the v2 fork targets first-class.
- DragonflyDB — Server flags —
--lock_on_hashtagsand theallow-undeclared-keysescape hatch. - Redis — Documentation — the command and cluster reference underneath both runtimes.
Related in this course
- E2 · The core — the chapter landing.
- E2.04.1 · The Elixir architecture — the reference runtime in depth.
- E2.04.2 · The Go gaps — the honest port status.
- E2.04.3 · Cross-runtime interop — v1 interop and the v2 trajectory.
- redis-patterns R3 · Reliable queues — the pattern these runtimes apply.