Absolutely! Here’s a condensed and comprehensive list of the breaking changes, changes, additions, fixes and removals between 1.2 and 2.0:
-
[Oban.Worker] 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.
To migrate change all worker definitions from accepting an args
map and a job
struct:
def perform(%{"id" => id}, _job), do: IO.inspect(id)
To accept a single job
struct and match on the args
key directly:
def perform(%Job{args: %{"id" => id}}), do: IO.inspect(id)
-
[Oban.Worker] The backoff/1
callback now expects a job struct instead of an integer. That allows applications to finely control backoff based on more than just the current attempt number. Use of backoff/1
with an integer is no longer supported.
To migrate change any worker definitions that used a raw attempt
like this:
def backoff(attempt), do: attempt * 60
To match on a job struct instead, like this:
def backoff(%Job{attempt: attempt}), do: attempt * 60
-
[Oban.Config] The :verbose
setting is renamed to :log
. The setting started off as a simple boolean, but it has morphed to align with the log values accepted by calls to Ecto.Repo
.
To migrate, replace any :verbose
declarations:
config :my_app, Oban,
verbose: false,
...
With use of :log
instead:
config :my_app, Oban,
log: false,
...
-
[Oban] The interface for start_queue/3
is replaced with start_queue/2
and stop_queue/2
no longer accepts a queue name as the second argument. Instead, both functions now accept a keyword list of options. This enables the new local_only
flag, which allows you to dynamically start and stop queues only for the local node.
Where you previously called start_queue/2,3
or stop_queue/2
like this:
:ok = Oban.start_queue(:myqueue, 10)
:ok = Oban.stop_queue(:myqueue)
You’ll now them with options, like this:
:ok = Oban.start_queue(queue: :myqueue, limit: 10)
:ok = Oban.stop_queue(queue: :myqueue)
Or, to only control the queue locally:
:ok = Oban.start_queue(queue: :myqueue, limit: 10, local_only: true)
:ok = Oban.stop_queue(queue: :myqueue, local_only: true)
-
[Oban] Replace drain_queue/3
with drain_queue/2
, which now has an interface consistent with the other *_queue/2
operations.
Where you previously called drain_queue/2,3
like this:
Oban.drain_queue(:myqueue, with_safety: false)
You’ll now it with options, like this:
Oban.drain_queue(queue: :myqueue, with_safety: false)
-
[Oban] The interface for pause_queue/2
, resume_queue/2
and scale_queue/3
now matches the recently changed start_queue/2
and stop_queue/2
. All queue manipulation functions now have a consistent interface, including the ability to work in :local_only
mode.
-
[Oban.Telemetry] The format for telemetry events has changed to match the new telemetry span
convention. This listing maps the old event to the new one:
-
[: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]
In addition, for exceptions the stacktrace meta key has changed from :stack
to the standardized :stacktrace
.
-
[Oban.Beat] Pulse tracking and periodic job rescue are no longer available. Pulse tracking and rescuing will be handled by an external plugin. This is primarily an implementation detail, but it means that jobs may be left in the executing
state after a crash or forced shutdown.
Remove any :beats_maxage
, :rescue_after
or :rescue_interval
settings from your config.
-
[Oban.Plugins.Pruner] Built in pruning is handled by the new plugin system. A fixed period pruning module is enabled as a default plugin. The plugin allows light configuration through a max_age
value. For customizable per-queue, per-worker or per-state pruning see the DynamicPruner
available in Oban Pro.
Remove any :prune
, :prune_interval
or prune_limit
settings from your config. To disable the pruning plugin in test mode set plugins: false
instead.
Replace any use of :prune
, :prune_interval
or :prune_limit
in your config and pass a max_age
value to the plugin:
config :my_app, Oban,
plugins: [{Oban.Plugins.Pruner, max_age: 60}]
...
-
[Oban.Scheduler] Ensure isolation between transaction locks in different prefixes. A node with multiple prefix-isolated instances (i.e. “public” and “private”) would always attempt to schedule cron jobs at the same moment. The first scheduler would acquire a lock and block out the second, preventing the second scheduler from ever scheduling jobs.
-
[Oban.Query] Correctly prefix unprepared unique queries. Unique queries always targeted the “public” prefix, which either caused incorrect results when there were both “public” and an alternate prefix. In situations where there wasn’t a public oban_jobs
table at all it would cause cryptic transaction errors.
-
[Oban.Query] Wrap all job fetching in an explicit transaction to enforce FOR UPDATE SKIP LOCKED
semantics. Prior to this it was possible to run the same job at the same time on multiple nodes.
-
[Oban.Crontab] Fix weekday matching for Sunday, which is represented as 0
in crontabs.
-
[Oban.Crontab.Cron] Do not raise an ArgumentError
exception when the crontab configuration includes a step of 1, which is a valid step value.
-
[Oban.Breaker] Prevent connection bomb when the Notifier
experiences repeated disconnections.
-
[Oban.Telemetry] Correctly record timings using native time units, but log them using microseconds. Previously they used a mixture of native and microseconds, which yielded inconsistent values.
-
[Oban.Telemetry] Stop logging the :error
value for circuit trip events. The error is a struct that isn’t JSON encodable. We include the normalized Postgrex / DBConnection message already, so the error is redundant.
-
[Oban.Worker] Support returning {:snooze, seconds}
from perform/1
to re-schedule a job some number of seconds in the future. This is useful for recycling jobs that aren’t ready to run yet, e.g. because of rate limiting.
-
[Oban.Worker] Support returning :discard
from perform/1
to immediately discard a job. This is useful when a job encounters an error that won’t resolve with time, e.g. invalid arguments or a missing record.
-
[Oban.Job] Introduce a virtual unsaved_error
field, which is populated with an error map after failed execution. The unsaved_error
field is set before any calls to the worker’s backoff/1
callback, allowing workers to calculate a custom backoff depending on the error that failed the job.
-
[Oban.Worker] Add :infinity
option for unique period.
-
[Oban] Bubble up errors and exits when draining queues by passing with_safety: false
as an option to Oban.drain_queue/3
.
-
[Oban] Add Oban.cancel_job/2
for safely discarding scheduled jobs or killing executing jobs. This deprecates kill_job/2
, which isn’t as flexible.
-
[Oban.Telemetry] Add span/3
for reporting normalized :start
, :stop
and :exception
events with timing information.
-
[Oban.Telemetry] Include the configured prefix
in all event metadata. This makes it possible to identify which schema prefix a job ran with, which is useful for differentiating errors in a multi-tenant system.
-
[Oban.Telemetry] Include queue_time
as a measurement with stop
and exception
events. This is a measurement in milliseconds of the amount of time between when a job was scheduled to run and when it was last attempted.
-
[Oban.Testing] Add perform_job/2,3
helper to automate validating, normalizing and performing jobs while unit testing. This is now the preferred way to unit test workers.
To update your tests replace any calls to perform/1,2
with the new Oban.Testing.perform_job/2,3
helper:
defmodule MyApp.WorkerTest do
use MyApp.DataCase, async: true
use Oban.Testing, repo: MyApp.Repo
alias MyApp.Worker
test "doing business in my worker" do
assert :ok = perform_job(Worker, %{id: 1})
end
end
The perform_job/2,3
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.
-
[Oban.Crontab] Add support for non-standard expressions such as @daily
, @hourly
, @midnight
, and @reboot
-
[Oban.Crontab] Add support for using step values in conjunction with ranges, enabling expressions like 10-30/2
, 15-45/3
, etc.
-
[Oban.Telemetry] Include job queue_time
in the default logger output.
-
[Oban.Telemetry] Add new :producer
events for descheduling and dispatching jobs from queue producers.