# Upgrading to v2.0

> This information is extracted and expanded from the [CHANGELOG](changelog.html).

This is a big release with a _ton_ of new features and fixes, but also a few
breaking changes. This guide will walk you through the upgrade process.

## Bump Your Deps

Update Oban to the latest version:

```elixir
  defp deps do
    [
      {:oban, "~> 2.0.0"}
      ...
    ]
  end
```

If you're an Oban Web+Pro user you'll also need to bump Oban.Web and add Oban.Pro:

```elixir
  defp deps do
    [
      {:oban, "~> 2.0.0"},
      {:oban_web, "~> 2.0.0", organization: "oban"},
      {:oban_pro, "~> 0.3.0", organization: "oban"}
      ...
    ]
  end
```

## Oban.Worker Changes

The `perform/2` callback is replaced with `perform/1`, where the only argument
is an Oban.Job struct. This unifies the interface for all Oban.Worker callbacks
and helps to eliminate confusion around pattern matching on arguments.

Change all worker definitions from accepting `args` and a `job` to only accept a
job and match on the nested `args` key:

```diff
- def perform(%{"id" => id}, _job)
+ def perform(%Job{args: %{"id" => id}})
```

For finer control of job backoff the `backoff/1` callback now expects a job
struct instead of an integer. Change any workers that expect an attempt number
to match on the full job struct:

```diff
- def backoff(attempt)
+ def backoff(%Job{attempt: attempt})
```

## Update Your Config

The `:verbose` setting was renamed to `:log` to better align with values
accepted by `Ecto.Repo`.

```diff
config :my_app, Oban,
- verbose: false,
+ log: false
  ...
```

Pruning is now handled by the new plugin system. Replace `:prune` in your config
and pass a `:max_age` value to the plugin:

```diff
config :my_app, Oban,
- prune: {:max_age, 60},
- prune_interval: 30_000,
- prune_limit: 5000,
+ plugins: [{Oban.Plugins.Pruner, max_age: 60}]
  ...
```

In test mode you can disable pruning by setting `plugins` to false instead:

```diff
config :my_app, Oban,
-  prune: false,
+  plugins: false
  ...
```

🌟 Oban.Pro users may opt to use the [DynamicPruner](dynamic_pruning.html)
instead for finer control. For example, to set per-state retention periods:

```elixir
config :my_app, Oban,
  plugins: [{
    Oban.Pro.Plugins.DynamicPruner,
    state_overrides: [
      completed: {:max_age, {1, :day}},
      discarded: {:max_age, {1, :month}}
    ]
  }]
  ...
```

Pulse tracking and orphaned job rescue are removed from base Oban. This change
means that you will need to manually rescue any jobs left executing state after
a crash or forced shutdown.

Remove any `:beats_maxage`, `:rescue_after` or `:rescue_interval` settings from
your config:

```diff
config :my_app, Oban,
-  beats_maxage: 10,
-  rescue_after: 30_000,
-  rescue_interval: 5_000
  ...
```

🌟 Oban.Pro users may use the [Lifeline](lifeline.html) plugin to retain
automatic orphaned job rescue with lightweight heartbeat recording:

```elixir
config :my_app, Oban,
  plugins: [Oban.Pro.Plugins.Lifeline]
  ...
```

## Update Your Tests

The new `perform_job` test helper automates validating, normalizing and
perform jobs in unit tests.

To update your tests replace any calls to `perform` with the new helper:

```diff
- assert :ok = MyApp.Worker.perform(%{id: 1}, %Oban.Job{})
+ assert :ok = perform_job(MyApp.Worker, %{id: 1})
```

The `perform_job` helper will verify the worker, the arguments and any
provided options. It will then verify that your worker returns a valid result
and return the value for you to assert on.

Within integration tests replace `drain_queue/3` with `drain_queue/2`:

```diff
- Oban.drain_queue(:myqueue, with_safety: false)
+ Oban.drain_queue(queue: :myqueue, with_safety: false)
```

## Update Telemetry

Telemetry event names have changed, along with some of the metadata and timing
units. The new event names are consistent and align with the now-standard
`telemetry:span` conventions.

Update handlers to match on the new event names:

```diff
- def handle_event([:oban, :failure], measure, meta, _) do
+ def handle_event([:oban, :job, :exception], measure, meta, _) do
```

And update the `attach` calls:

```diff
- :telemetry.attach("oban", [[:oban, :failure]], &handle_event/4, %{})
+ :telemetry.attach("oban", [[:oban, :job, :exception]], &handle_event/4, %{})
```

Finally, replace references to `meta.stack` with `meta.stacktrace`:

```diff
- Sentry.capture_exception(meta.error, stacktrace: meta.stack, extra: extra)
+ Sentry.capture_exception(meta.error, stacktrace: meta.stacktrace, extra: extra)
```

Here is a conversion chart for any other handlers you may have:

```text
[:oban, :started] -> [:oban, :job, :start]
[:oban, :success] -> [:oban, :job, :stop]
[:oban, :failure] -> [:oban, :job, :exception]
[:oban, :trip_circuit] -> [:oban, :circuit, :trip]
[:oban, :open_circuit] -> [:oban, :circuit, :open]
```

## Update Oban.Web (Optional)

Oban.Web is streamlined to share configuration with Oban and use the new plugin
system. Remove any Oban.Web specific configuration:

```diff
- config :my_app, Oban.Web, repo: MyApp.Repo
```

Next, add the necessary plugins to the Oban config:

```elixir
config :my_app, Oban,
  plugins: [
    Oban.Pro.Plugins.DynamicPruner,
    Oban.Pro.Plugins.Lifeline,
    Oban.Web.Plugins.Stats
  ],
  ...
```

Now remove ObanWeb from your application's supervision tree:

```diff
children = [
  MyApp.Repo,
  MyApp.Endpoint,
  {Oban, oban_opts},
- {ObanWeb, oban_web_opts}
]
```

And delete any existing `ObanWeb` migrations:

```diff
- defdelegate up, to: ObanWeb.Migrations
- defdelegate down, to: ObanWeb.Migrations
```

Finally, use the `oban_dashboard` macro to easily mount in your router:

```diff
+ import Oban.Web.Router

scope "/" do
  pipe_through :browser

-  live "/oban", ObanWeb.DashboardLive, layout: {ObanWeb.LayoutView, "app.html"}
+  oban_dashboard("/oban")
end
```
