Operations

Dashboard

Mount the engine to see queues, jobs, failures, and dead letters — auto-refreshing over Turbo Frames.

Mount it#

config/routes.rb
mount Pgbus::Engine => "/pgbus"

The dashboard is a mountable Rails engine. Every table auto-refreshes over Turbo Frames — no WebSocket, no Action Cable. Destructive actions use styled confirmation dialogs and flash as toast notifications.

The panels#

PanelShows
OverviewA health verdict strip (OK / DEGRADED / STALLED with its reasons — what /readyz would say), then cards that each say what their number means and link to the page that explains it: queues (paused, dead-letter, undrained), enqueued, processes (healthy, stalled, stale), recurring tasks, retrying (next attempt, newest error), dead-lettered (newest reason), throughput (jobs/min over 5 minutes, from job stats) and parked jobs. The queues table says what each queue is doing; Queue Health states its thresholds.
QueuesPer-queue metrics with purge / pause / resume / delete.
JobsEnqueued and failed jobs, with retry / discard.
Dead letterNew dead messages show why they died — the last recorded error when available, attempts, and source queue — filterable by DLQ and error class, with retry / discard and bulk actions.
ProcessesEvery process with its status in words: why it is Healthy, Stalled or Stale against which limit, and what happens next (the supervisor's watchdog restarts it, the dispatcher removes it within 5 minutes, or nothing will). Each row also says what the process is doing (queues or topics, busy threads, buffered claims, jobs/s), how close it is to a recycle (1,240 / 10,000 jobs · 310 / 512 MB · up 42m 0s / 1h 0m), its uptime and its supervisor.
EventsPending events with their state, the handler that runs each one and why it waits (or which attempt failed with what error); processed events say whether each claim completed, is being handled or went silent, with Replay when the claim completed, its handler is still registered and the archive still holds the event; subscribers say whether a running consumer drains them.
OutboxTransactional outbox entries pending publication.
LocksUniqueness locks and concurrency keys — value, limit, lease, parked jobs; release a key or discard its parked jobs.
InsightsThroughput and status distribution charts, each with a caption saying what it shows and a data table behind it, themed for light and dark mode; slowest job classes. The queue latency chart and latency by queue appear once rails generate pgbus:add_job_stats_latency has added the latency columns.
The Insights page reads pgbus_job_stats — add it with rails generate pgbus:add_job_stats. Stats are buffered and bulk-inserted; if the migration hasn't run, recording is silently skipped.

Every process registers its start time, and processes the supervisor forks register its pid. Workers and consumers refresh their pool's capacity and busy count, buffered claims, RSS, processed/handled counts and recycle limits (a worker uses its capsule's own limits when set) once per 60 s beat, never per job. Workers also report live rates; consumers do not. A process from before these keys existed shows "—" where a fact is missing. A row is grouped under a supervisor only when that supervisor's row is on the same host. The stall limits the page quotes are derived from the dashboard host's stall_threshold: workers get it as is, dispatchers and schedulers add their sleep interval, consumers add their polling allowance.

Protect it in production#

The dashboard has no auth of its own.

Guard the mounted engine with a web_auth lambda:

config/initializers/pgbus.rb
Pgbus.configure do |config|
  config.web_auth = ->(request) { request.env["warden"]&.user&.admin? }
end

Or inherit from your own authenticated controller — then its before_action filters and helpers apply automatically, with no monkey-patching:

Pgbus.configure do |config|
  config.base_controller_class = "Admin::BaseController"
  config.return_to_app_url     = "/admin" # adds a "back to app" button
end
The dashboard exposes queue contents and destructive actions (purge, delete, discard). Never mount it unauthenticated in production.