Adoption

Oban Pro layers enhanced functionality on top of Oban through extensions, plugins, and workers. Those enhancements are all optional and require a little configuration to enable.

This guide will walk you through the minimum configuration changes you should make to start utilizing Pro along with some optional suggestions to hint at what's possible.

1. Pro Engine

The Pro engine is the brains behind much of Pro's advanced capabilities and added reliability. It brings global concurrency limits, distributed rate limiting, partitioned limiting, unique bulk job inserts, and precise orphaned job rescuing.

The Pro engine utilizes centralized producer records to coordinate between nodes with minimal load on the database (and without any reliance on Distributed Erlang clustering).

To start, create a migration:

$ mix ecto.gen.migration add_oban_pro

Within the migration module:

use Ecto.Migration

def up, do: Oban.Pro.Migration.up()

def down, do: Oban.Pro.Migration.down()

This creates the various tables and indexes used by Pro's engine and plugins.

Next, update your config to use the Pro engine:

  config :my_app, Oban,
+   engine: Oban.Pro.Engine,
    repo: MyApp.Repo
    ...

💡 Explore Queue Options

2. Pro Services

Pro ships drop-in replacements for Oban's built-in Cron, Lifeline, and Pruner services. Each keeps the same core behavior while adding runtime configuration and Pro engine awareness. Swap all three at once by pointing the service keys at their Pro counterparts and moving any options into the service tuple:

  config :my_app, Oban,
    engine: Oban.Pro.Engine,
-   cron: [crontab: [...]],
-   lifeline: Oban.Plugins.Lifeline,
-   pruner: [max_age: {7, :days}]
-   queues: [default: 10],
+   cron: {Oban.Pro.Cron, crontab: [...]},
+   lifeline: Oban.Pro.Lifeline,
+   pruner: {Oban.Pro.Pruner, mode: {:max_age, {7, :days}}},
+   queues: {Oban.Pro.Queues, queues: [default: 10]}
    ...
  • Lifeline rescues orphaned jobs from producer records rather than a time-based grace period, so it's always accurate and no longer needs rescue_after.

  • Cron uses the same crontab, but persists entries so you can add, update, or remove them at runtime.

  • Pruner replaces a single global age with per-state, per-queue, and per-worker rules; mode sets the default retention.

💡 Explore Services and Plugins

  • Use Queues as the top-level :queues service to define and reconfigure queues at runtime, and have those changes persist between restarts.

  • Keep low-priority jobs from starving with DynamicPrioritizer, which gradually bumps their priority until they run.

  • Autoscale cloud infrastructure to match demand with DynamicScaler, spinning nodes up during traffic and back down during a lull.

3. Pro.Worker

The Oban.Pro.Worker is a replacement for Oban.Worker with expanded capabilities such as encryption, enforced structure, output recording, and execution hooks.

Upgrade all of your workers to Pro workers by switching out the use module and replacing perform/1 with process/1:

  def MyApp.Worker do
-   use Oban.Worker
+   use Oban.Pro.Worker

-   @impl Oban.Worker
-   def perform(%Job{} = job) do
-     # Do stuff with the job
-   end
+   @impl Oban.Pro.Worker
+   def process(%Job{} = job) do
+     # Do stuff with the job
+   end
  end

Only Pro workers support execution hooks, which are especially helpful as a reliable alternative to telemetry for error reporting. Once you've modified existing workers you can define a global error hook (be sure to remove any existing telemetry backed error hooks):

defmodule MyApp.ErrorHook do
  def after_process(state, job) when state in [:discard, :error] do
    error = job.unsaved_error
    extra = Map.take(job, [:attempt, :id, :args, :max_attempts, :meta, :queue, :worker])

    Sentry.capture_exception(error.reason, stacktrace: error.stacktrace, extra: extra)

    :ok
  end

  def after_process(_state, _job), do: :ok
end

Oban.Pro.Worker.attach_hook(MyApp.ErrorHook)

💡 Explore Pro Workers

  • Validate args on insert and atomize them during execution with structured jobs.

  • Stash a job's return value to retrieve it later manually or as part of a workflow with recorded jobs.

  • Store all job data at rest with encrypted jobs so that sensitive data can't be seen in the clear.

  • Execute callbacks synchronously, from within the job's process after jobs finish executing with worker hooks

  • Process jobs in groups while tracking overall progress with Batches.

  • Compose jobs together with arbitrary dependencies using Workflows.

  • Process jobs in strict sequential order regardless of retries using Chains

4. Oban.Pro.Testing

Switch from Oban.Testing to Oban.Pro.Testing to more easily test workers, drain queues reliably, supervise test instances, and make assertions about enqeueud jobs.

 defmodule MyApp.Case do
   use ExUnit.CaseTemplate

   using do
     quote do
-      use Oban.Testing, repo: MyApp.Repo
+      use Oban.Pro.Testing, repo: MyApp.Repo
     end
   end
 end

Switch to drain_jobs/1

Oban.Pro.Testing.drain_jobs/1 replaces the standard Oban.drain_queue/2. The Pro version is designed to work with Pro workers and composition tools such as Workflows.

- %{success: 3} = Oban.drain_queue(queue: :default)
+ %{completed: 3} = Oban.Pro.Testing.drain_jobs()

The Pro version returns counts using the actual job statuses, or even the full jobs rather than a count.

Continue with the testing guide for additional setup tips, or skip straight into the Oban.Pro.Testing docs to explore all of the testing functions.

5. Usage Rules (Optional)

Oban Pro ships with usage rules—reference documents that help AI coding assistants understand Pro's idioms and best practices. If you use Claude Code, Cursor, Windsurf, or similar tools, enable usage rules to get better suggestions when working with Pro.

Add the usage_rules package to your dependencies:

{:usage_rules, "~> 1.2"}

Then configure it in mix.exs to include Oban Pro's rules:

defp usage_rules do
  [
    usage_rules: [:oban_pro, ...]
  ]
end

Then run:

mix deps.get && mix usage_rules.sync

The rules cover workers, queues, composition (workflows, batches, chains, chunks), plugins, and testing. Re-run mix usage_rules.sync after upgrading Pro to get updated rules.