Guide

ActiveJob adapter

Set the adapter to :pgbus and your existing jobs run on PGMQ, unchanged.

Set the adapter#

pgbus is a standard ActiveJob queue adapter. Point Rails at it and every job in your app enqueues through PGMQ:

config/application.rb
config.active_job.queue_adapter = :pgbus
Because it's a standard adapter, nothing about your job classes changes — no base-class swap, no per-job include. queue_as, retry_on, and discard_on all work as usual.

Enqueue and schedule#

Your existing jobs work with no edits:

app/jobs/order_confirmation_job.rb
class OrderConfirmationJob < ApplicationJob
  queue_as :mailers

  def perform(order)
    OrderMailer.confirmation(order).deliver_now
  end
end

OrderConfirmationJob.perform_later(order)                    # enqueue now
OrderConfirmationJob.set(wait: 5.minutes).perform_later(order) # scheduled

A scheduled job is sent with a PGMQ delay, so it stays invisible until its time arrives — no separate scheduler poll table.

What happens to a message#

Enqueue, read, execute, archive — or dead-letter.

Each job becomes one PGMQ message. The adapter serializes it to JSON and sends it to the queue; a worker claims it under a visibility timeout, runs it inside the Rails executor, and archives it on success. On failure the visibility timeout expires and the message is retried — until read_ct crosses max_retries, when it routes to the dead-letter queue.

Success archives the message; repeated failures raise read_ct until it crosses max_retries and routes to the DLQ.

The retry backoff and dead-letter details are on Retries & dead letters.

Serialization and safety#

Payloads are JSON only — pgbus never uses Marshal, so a malicious or corrupt payload can't deserialize into arbitrary Ruby. GlobalID arguments (an Active Record record) resolve the same way they do under any adapter.

Need at-most-once semantics or a concurrency cap? See Concurrency & uniquenessensures_uniqueness and limits_concurrency layer straight onto a job class.