View Source Changelog for Oban v2.14

🌟 Looking for changes to Web or Pro? Check the Oban.Pro Changelog or the Oban.Web Changelog. 🌟

Time marches on, and we minimally support Elixir 1.12+, PostgreSQL 12+, and SQLite 3.37.0+

sqlite3-support-with-the-lite-engine

🪶 SQLite3 Support with the Lite Engine

Increasingly, developers are choosing SQLite for small to medium-sized projects, not just in the embedded space where it's had utility for many years. Many of Oban's features, such as isolated queues, scheduling, cron, unique jobs, and observability, are valuable in smaller or embedded environments. That's why we've added a new SQLite3 storage engine to bring Oban to smaller, stand-alone, or embedded environments where PostgreSQL isn't ideal (or possible).

There's frighteningly little configuration needed to run with SQLite3. Migrations, queues, and plugins all "Just Work™".

To get started, add the ecto_sqlite3 package to your deps and configure Oban to use the Oban.Engines.Lite engine:

config :my_app, Oban,
  engine: Oban.Engines.Lite,
  queues: [default: 10],
  repo: MyApp.Repo

Presto! Run the migrations, include Oban in your application's supervision tree, and then start inserting and executing jobs as normal.

⚠️ SQLite3 support is new, and while not experimental, there may be sharp edges. Please report any issues or gaps in documentation.

smarter-job-fetching

👩‍🔬 Smarter Job Fetching

The most common cause of "jobs not processing" is when PubSub isn't available. Our troubleshooting section instructed people to investigate their PubSub and optionally include the Repeater plugin. That kind of manual remediation isn't necessary now! Instead, we automatically switch back to local polling mode when PubSub isn't available—if it is a temporary glitch, then fetching returns to the optimized global mode after the next health check.

Along with smarter fetching, Stager is no longer a plugin. It wasn't ever really a plugin, as it's core to Oban's operation, but it was treated as a plugin to simplify configuration and testing. If you're in the minority that tweaked the staging interval, don't worry, the existing plugin configuration is automatically translated for backward compatibility. However, if you're a stickler for avoiding deprecated options, you can switch to the top-level stage_interval:

config :my_app, Oban,
  queues: [default: 10],
- plugins: [{Stager, interval: 5_000}]
+ stage_interval: 5_000

comprehensive-telemetry-data

📡 Comprehensive Telemetry Data

Oban has exposed telemetry data that allows you to collect and track metrics about jobs and queues since the very beginning. Telemetry events followed a job's lifecycle from insertion through execution. Still, there were holes in the data—it wasn't possible to track the exact state of your entire Oban system through telemetry data.

Now that's changed. All operations that change job state, whether inserting, deleting, scheduling, or processing jobs report complete state-change events for every job including queue, state, and worker details. Even bulk operations such as insert_all_jobs, cancel_all_jobs, and retry_all_jobs return a subset of fields for all modified jobs, rather than a simple count.

See the 2.14 upgrade guide for step-by-step instructions (all two of them).

v2-14-0-2023-01-25

v2.14.0 — 2023-01-25

enhancements

Enhancements

  • [Oban] Store a {:cancel, :shutdown} error and emit [:oban, :job, :stop] telemetry when jobs are manually cancelled with cancel_job/1 or cancel_all_jobs/1.

  • [Oban] Include "did you mean" suggestions for Oban.start_link/1 and all nested plugins when a similar option is available.

    Oban.start_link(rep: MyApp.Repo, queues: [default: 10])
    ** (ArgumentError) unknown option :rep, did you mean :repo?
        (oban 2.14.0-dev) lib/oban/validation.ex:46: Oban.Validation.validate!/2
        (oban 2.14.0-dev) lib/oban/config.ex:88: Oban.Config.new/1
        (oban 2.14.0-dev) lib/oban.ex:227: Oban.start_link/1
        iex:1: (file)
  • [Oban] Support scoping queue actions to a particular node.

    In addition to scoping to the current node with :local_only, it is now possible to scope pause, resume, scale, start, and stop queues on a single node using the :node option.

    Oban.scale_queue(queue: :default, node: "worker.123")
  • [Oban] Remove retry_job/1 and retry_all_jobs/1 restriction around retrying scheduled jobs.

  • [Job] Restrict replace option to specific states when unique job's have a conflict.

    # Replace the scheduled time only if the job is still scheduled
    SomeWorker.new(args, replace: [scheduled: [:schedule_in]], schedule_in: 60)
    
    # Change the args only if the job is still available
    SomeWorker.new(args, replace: [available: [:args]])
  • [Job] Introduce format_attempt/1 helper to standardize error and attempt formatting across engines

  • [Repo] Wrap nearly all Ecto.Repo callbacks.

    Now every Ecto.Repo callback, aside from a handful that are only used to manage a Repo instance, are wrapped with code generation that omits any typespecs. Slight inconsistencies between the wrapper's specs and Ecto.Repo's own specs caused dialyzer failures when nothing was genuinely broken. Furthermore, many functions were missing because it was tedious to manually define every wrapper function.

  • [Peer] Emit telemetry events for peer leadership elections.

    Both peer modules, Postgres and Global, now emit [:oban, :peer, :election] events during leader election. The telemetry meta includes a leader? field for start and stop events to indicate if a leadership change took place.

  • [Notifier] Allow passing a single channel to listen/2 rather than a list.

  • [Registry] Add lookup/2 for conveniently fetching registered {pid, value} pairs.

bug-fixes

Bug Fixes

  • [Basic] Capture StaleEntryError on unique replace.

    Replacing while a job is updated externally, e.g. it starts executing, could occasionally raise an Ecto.StaleEntryError within the Basic engine. Now, that exception is translated into an error tuple and bubbles up to the insert call site.

  • [Job] Update t:Oban.Job/0 to indicate timestamp fields are nullable.

deprecations

Deprecations

  • [Stager] Deprecate the Stager plugin as it's part of the core supervision tree and may be configured with the top-level stage_interval option.

  • [Repeater] Deprecate the Repeater plugin as it's no longer necessary with hybrid staging.

  • [Migration] Rename Migrations to Migration, but continue delegating functions for backward compatibility.

For changes prior to v2.14 see the v2.13 docs.