Upgrading to v2.0 View Source
This information is extracted and expanded from the CHANGELOG.
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:
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:
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:
- 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:
- 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
.
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:
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:
config :my_app, Oban,
- prune: false,
+ plugins: false
...
🌟 Oban.Pro users may opt to use the DynamicPruner instead for finer control. For example, to set per-state retention periods:
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:
config :my_app, Oban,
- beats_maxage: 10,
- rescue_after: 30_000,
- rescue_interval: 5_000
...
🌟 Oban.Pro users may use the Lifeline plugin to retain automatic orphaned job rescue with lightweight heartbeat recording:
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:
- 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
:
- 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 and match on the new event names:
- def handle_event([:oban, :failure], measure, meta, _) do
+ def handle_event([:oban, :job, :exception], measure, meta, _) do
And update the attach
calls:
- :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
:
- 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:
[: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:
- config :my_app, Oban.Web, repo: MyApp.Repo
Next, add the necessary plugins to the Oban config:
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:
children = [
MyApp.Repo,
MyApp.Endpoint,
{Oban, oban_opts},
- {ObanWeb, oban_web_opts}
]
And delete any existing ObanWeb
migrations:
- defdelegate up, to: ObanWeb.Migrations
- defdelegate down, to: ObanWeb.Migrations
Finally, use the oban_dashboard
macro to easily mount in your router:
+ import Oban.Web.Router
scope "/" do
pipe_through :browser
- live "/oban", ObanWeb.DashboardLive, layout: {ObanWeb.LayoutView, "app.html"}
+ oban_dashboard("/oban")
end