# Changelog for Oban v2.12
_🌟 Looking for changes to Web or Pro? Check the [Oban.Pro Changelog][opc] or
the [Oban.Web Changelog][owc]. 🌟_
[Oban v2.12 Upgrade Guide](v2-12.html)
Oban v2.12 was dedicated to enriching the testing experience and expanding
config, plugin, and queue validation across all environments.
## Testing Modes
Testing modes bring a new, vastly improved, way to configure Oban for testing.
The new `testing` option makes it explicit that Oban should operate in a
restricted mode for the given environment.
Behind the scenes, the new testing modes rely on layers of validation within
Oban's `Config` module. Now production configuration is validated automatically
during test runs. Even though queues and plugins aren't _started_ in the test
environment, their configuration is still validated.
To switch, stop overriding `plugins` and `queues` and enable a testing mode
in your `test.exs` config:
config :my_app, Oban, testing: :manual
Testing in `:manual` mode is identical to testing in older versions of Oban:
jobs won't run automatically so you can use helpers like `assert_enqueued` and
execute them manually with `Oban.drain_queue/2`.
An alternate `:inline` allows Oban to bypass all database interaction and run
jobs _immediately in the process that enqueued them_.
config :my_app, Oban, testing: :inline
Finally, new [testing guides][tst] cover test setup, unit [testing
workers][tsw], integration [testing queues][tsq], and testing [dynamic
## Global Peer Module
Oban v2.11 introduced centralized leadership via Postgres tables. However,
Postgres based leadership isn't always a good fit. For example, an ephemeral
leadership mechanism is preferred for integration testing.
In that case, you can make use of the new `:global` powered peer module for
config :my_app, Oban,
## v2.12.1 — 2022-05-24
### Bug Fixes
- [BasicEngine] Never fetch jobs that have reached max attempts
This adds a safeguard to the `fetch_jobs` function to prevent ever hitting the
`attempt <= max_attempts` check constraint. Hitting the constraint causes the
query to fail, which crashes the producer and starts an infinite loop of
crashes. The previous commit _should_ prevent this situation from ocurring at
the "staging" level, but to be absolutely safe this change prevents it at the
"fetching" level too.
There is a very minor performance hit from this change because the query can
no longer run as an index only scan. For systems with a modest number of
available jobs the performance impact is indistinguishable.
- [Plugins] Prevent unexpectedly modifying jobs selected by subqueries
Most applications don't run at a serializable isolation level. That allows
subqueries to run within a transaction without having the conditions
rechecked—only predicates on `UPDATE` or `DELETE` are re-checked, not on
subqueries. That allows a race condition where rows may be updated without
- [Repo] Set `query_opts` in `Repo.transaction` options to prevent logging
`begin` and `commit` events in development loggers.
- [BasicEngine] Remove the `ORDER BY` clause from unique queries
The previous `ORDER BY id DESC` significantly hurts unique query performance
when there are a _lot_ of potential jobs to check. The ordering was originally
added to make test cases predictable and isn't important for the actual
behaviour of the unique check.
## v2.12.0 — 2022-04-19
- [Oban] Replace queue, plugin, and peer test configuration with a single
`:testing` option. Now configuring Oban for testing only requires one change,
setting the test mode to either `:inline` or `:manual`.
- `:inline`—jobs execute immediately within the calling process and without
touching the database. This mode is simple and may not be suitable for apps
with complex jobs.
- `:manual`—jobs are inserted into the database where they can be verified and
executed when desired. This mode is more advanced and trades simplicity for
- [Testing] Add `with_testing_mode/2` to temporarily change testing modes
within the context of a function.
Once the application starts in a particular testing mode it can't be changed.
That's inconvenient if you're running in `:inline` mode and don't want a
particular job to execute inline.
- [Config] Add `validate/1` to aid in testing dynamic Oban configuration.
- [Config] Validate full plugin and queue options on init, without the need
to start plugins or queues.
- [Peers.Global] Add an alternate `:global` powered peer module.
- [Plugin] A new `Oban.Plugin` behaviour formalizes starting and validating
plugins. The behaviour is implemented by all plugins, and is the foundation of
enhanced config validation.
- [Plugin] Emit `[:oban, :plugin, :init]` event on init from every plugin.
### Bug Fixes
- [Executor ] Skip timeout check with an unknown worker
When the worker can't be resolved we don't need to check the timeout. Doing so
prevents returning a helpful "unknown worker" message, and instead causes a
function error for `nil.timeout/1`.
- [Testing] Include `log` and `prefix` in generated conf for `perform_job`.
The opts, and subsequent conf, built for `perform_job` didn't include the
`prefix` or `log` options. That prevented functions that depend on a job's
`conf` within `perform/1` from running with the correct options.
- [Drainer] Retain the currently configured engine while draining a queue.
- [Watchman] Skip pausing queues when shutdown is immediate. This prevents
queue's from interacting with the database during short test runs.
For changes prior to v2.12 see the [v2.11][prv] docs.