3 KiB
3 KiB
Workers
Use Oban.Pro.Worker with args_schema for type-safe, validated job arguments:
defmodule MyApp.SomeWorker do
use Oban.Pro.Worker, queue: :default, max_attempts: 3
args_schema do
field :user_id, :integer, required: true
field :status, :enum, values: ~w(pending active)a, default: :pending
field :metadata, :map
end
@impl Oban.Pro.Worker
def process(%Oban.Job{args: %__MODULE__{} = args}) do
:ok
end
end
Structured Args
Validates data when calling new/1, before insertion. Notable types:
:enum- Validates and casts to atoms:field :status, :enum, values: ~w(pending completed)a:term- Safely encodes any Elixir term:uuid- Alias for:binary_id{:array, *}- Lists of typed values
Nested structures with embeds_one and embeds_many:
args_schema do
field :order_id, :integer, required: true
embeds_one :customer, required: true do
field :customer_id, :integer, required: true
end
embeds_many :line_items do
field :product_id, :integer, required: true
field :quantity, :integer, required: true
end
end
Uniqueness
Configure uniqueness with state groups, not explicit state lists:
# Good — uses the :incomplete group
use Oban.Pro.Worker, unique: [period: 60, states: :incomplete]
# Bad — explicit state lists drift out of sync with new states
use Oban.Pro.Worker, unique: [period: 60, states: [:available, :scheduled, :executing]]
Available groups: :incomplete (everything except :cancelled, :completed, :discarded) and
:scheduled (just the scheduled state, safe for debouncing). Explicit lists silently miss states
added in later releases and cause subtle duplication bugs.
Encrypted jobs
Protect sensitive args with transparent encryption:
use Oban.Pro.Worker,
queue: :default,
encrypted: [key: {Application, :fetch_env!, [:my_app, :oban_key]}]
Important: Only args are encrypted, never put sensitive data in meta.
Hooks
Execution hooks:
before_new/2— modify args/opts before job creationbefore_process/1— runs beforeprocess/1after_process/3— runs afterprocess/1with state (:complete,:cancel,:discard,:error,:snooze), job, and result
External state hooks:
on_cancelled/2— job cancelled externally (manual, deadline, dependency)on_discarded/2— job discarded by DynamicLifeline
@impl Oban.Pro.Worker
def after_process(state, job, result) do
if state in [:error, :discard], do: notify_error(job)
:ok
end
Attach hooks explicitly or globally:
use Oban.Pro.Worker, hooks: [MyApp.ErrorHook]
# Global hooks (in application startup)
Oban.Pro.Worker.attach_hook(:errors, MyApp.ErrorHook)
Deadlines
Cancel jobs that don't run within a time limit:
use Oban.Pro.Worker, deadline: {1, :hour}
# Override at runtime
MyWorker.new(%{}, deadline: {30, :minutes})
# Force cancel already-running jobs
use Oban.Pro.Worker, deadline: [in: {10, :minutes}, force: true]