Upgrading to v1.8

This release introduces workflow compensations, cursor-based backfills, inline cron annotations, external recorded storage, and persisted pruning rules with archiving. It also adopts Oban's dedicated service configuration and replaces the chain and chunk indexes for improved performance.

A database migration is required. All configuration changes are optional and can be adopted incrementally.

Bump Your Deps

Update Oban and Pro to the latest versions:

{:oban, "~> 2.24"},
{:oban_pro, "~> 1.8.0", repo: "oban"},

Run Oban.Pro.Migration (Required)

Oban Pro v1.8 drops _old indexes created by the v1.7 migration, adds tables for persisted Oban.Pro.Pruner rules and archived jobs, columns for workflow compensations, and an index for backfills. Generate a new migration and run Oban.Pro.Migration:

defmodule MyApp.Repo.Migrations.UpgradeObanProToV180 do
  use Ecto.Migration

  def up, do: Oban.Pro.Migration.up(version: "1.8.0")
  def down, do: Oban.Pro.Migration.down(version: "1.8.0")
end

On large oban_jobs tables, split the schema and index changes so indexes are created concurrently without blocking writes:

defmodule MyApp.Repo.Migrations.UpgradeObanProSchemasToV180 do
  use Ecto.Migration

  def up, do: Oban.Pro.Migration.up(version: "1.8.0", only: :schemas)
  def down, do: Oban.Pro.Migration.down(version: "1.8.0", only: :schemas)
end

Then run the index migration outside a transaction:

defmodule MyApp.Repo.Migrations.UpgradeObanProIndexesToV180 do
  use Ecto.Migration

  @disable_migration_lock true
  @disable_ddl_transaction true

  def up, do: Oban.Pro.Migration.up(version: "1.8.0", only: :indexes)
  def down, do: Oban.Pro.Migration.down(version: "1.8.0", only: :indexes)
end

The migration lock doesn't need to be disabled when the repo uses advisory migration locks.

The Smart engine is now Oban.Pro.Engine. Update your configuration to use the shorter module name:

 config :my_app, Oban,
-  engine: Oban.Pro.Engines.Smart
+  engine: Oban.Pro.Engine

The old module remains available for compatibility and won't emit deprecation warnings.

Oban v2.24 adds top-level options for cron, lifeline, and pruner, while queues accepts the same {module, options} form. Move the corresponding Pro modules out of :plugins and use their shorter names:

 config :my_app, Oban,
-  queues: false,
-  plugins: [
-    {Oban.Pro.Plugins.DynamicCron, crontab: [...]},
-    Oban.Pro.Plugins.DynamicLifeline,
-    {Oban.Pro.Plugins.DynamicPruner, mode: {:max_age, {7, :days}}},
-    {Oban.Pro.Plugins.DynamicQueues, 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]}

The old modules and :plugins configuration remain available and won't emit deprecation warnings on startup. However, calls to runtime management functions on the old modules are deprecated, and you should use the corresponding functions on Oban.Pro.Cron, Oban.Pro.Pruner, or Oban.Pro.Queues instead.

Replace Pruner Overrides with Rules (Optional)

The mode and *_overrides options still work and are automatically translated into rules. To use compound matches, explicit ordering, runtime updates, or archiving, replace all legacy options with rules at the same time:

 pruner: {
   Oban.Pro.Pruner,
-  mode: {:max_age, {7, :days}},
-  queue_overrides: [events: {:max_age, {10, :minutes}}],
-  state_overrides: [discarded: {:max_age, {2, :days}}],
-  worker_overrides: ["MyApp.SecretWorker": {:max_age, {1, :second}}]
+  rules: [
+    [name: "queue-events", queue: :events, max_age: {10, :minutes}],
+    [name: "state-discarded", state: :discarded, max_age: {2, :days}],
+    [name: "worker-MyApp.SecretWorker", worker: MyApp.SecretWorker, max_age: {1, :second}],
+    [name: "default", max_age: {7, :days}]
+  ]
 }

Rules use first-match precedence, so preserve the legacy queue, state, worker, and default order unless you intentionally want different behavior. Don't combine rules with mode or any *_overrides; mixed configuration prevents the Pruner from starting.

Add the Mix Compiler for Cron Annotations (Optional)

Cron discovery is registered at compile time by a Mix compiler. Add :oban_pro to your project's compilers: list after the standard Mix compilers so the worker beams exist when it scans:

def project do
  [
    ...,
+    compilers: Mix.compilers() ++ [:oban_pro]
  ]
end

In umbrella projects, add it to each child app that defines annotated workers.

If a worker or decorated function uses cron: without the compiler in place, the first compile will warn you with the same instructions.

When you start using cron: on workers or decorators, also set sync_mode: :automatic on the plugin so removed or renamed annotations clean up their persisted entries:

cron: {
  Oban.Pro.Cron,
+  sync_mode: :automatic,
  crontab: [...]
}

Without automatic sync, removing a cron: annotation leaves an orphaned database row that has to be deleted manually (or with a one-off delete: true entry).

See Discovering Annotated Workers and Automatic Synchronization for full details.