Guide
Architecture
A supervisor forks workers that move messages through PGMQ's tables; the dashboard reads the same tables.
The shape of it#
Everything an app does — enqueue a job, publish an event, broadcast an update — goes through one door, Pgbus::Client, into PGMQ's queue tables. A supervisor forks workers that read and execute; a dispatcher runs the periodic maintenance; the dashboard reads the very same tables.
The layers#
From configuration up to the dashboard.
pgbus is organized as a stack — each layer depends only on the ones below it. You interact with the top; the invariants live at the bottom.
| Layer | What it does |
|---|---|
| Dashboard | The mounted Rails engine — queues, jobs, failures, dead letters. |
| CLI | pgbus start |
| Process model | Supervisor, worker, dispatcher, consumer, outbox poller. |
| Event bus | Publisher, subscriber registry, topic routing, idempotent handlers. |
| ActiveJob | The adapter + executor that serialize and run jobs. |
| Client | Pgbus::Client |
| Configuration | Every knob, resolved once at boot. |
The invariant that keeps the stack honest: all PGMQ access goes through Pgbus::Client — queue prefixing, visibility timeouts, and dead-letter routing are enforced there, not scattered across callers.
The processes a supervisor manages#
pgbus start boots a supervisor (a fork manager). It supervises:
| Process | Responsibility |
|---|---|
| Worker | Reads a queue (or wakes via LISTEN/NOTIFY), executes jobs, recycles itself. |
| Dispatcher | Maintenance: idempotency cleanup, archive compaction, stale-process reaping, the circuit breaker. |
| Scheduler | Enqueues recurring tasks on their cron schedule. |
| Consumer | Reads event-bus topic queues and runs handlers. |
| Outbox poller | Moves committed outbox rows into PGMQ (when the outbox is enabled). |
How a job flows through the system#
- Enqueue — Active Job serializes the job to JSON; pgbus sends it to the appropriate PGMQ queue through
Pgbus::Client. - Read — a worker polls the queue (or wakes instantly via LISTEN/NOTIFY) and claims the message with a visibility timeout, so no other worker takes it.
- Execute — the job is deserialized and run inside the Rails executor.
- Archive or retry — on success the message is archived to the
a_<queue>table; on failure the visibility timeout expires and the message becomes available again. PGMQ'sread_ctcounts delivery attempts. - Dead letter — when
read_ctexceedsmax_retries, the message moves to the<queue>_dlqqueue for inspection instead of retrying forever.
The message lifecycle has its own picture in Retries & dead letters.