towerops/vendor/oban_pro/usage-rules/workers.md
Graham McIntire 6c05d45dd6 deps: upgrade oban_pro to 1.7.0
Bumps vendored Oban Pro from 1.6.13 to 1.7.0, which transitively bumps
oban core to 2.22.1 (requires migrations v14) and db_connection to 2.10.0.

- mix.exs constraint: ~> 1.6 → ~> 1.7
- vendor/oban_pro/ replaced with v1.7.0 hex package
- migration 20260430142200: Oban core v12 → v14 (must run first)
- migration 20260430142241: Oban Pro 1.7.0 schema additions

Also corrects a pre-existing constraint name in AgentAssignment that was
left stale by the equipment→devices rename migration (20260117190134).
The unique index is named agent_assignments_device_id_index, but the
schema's unique_constraint/3 still pointed at the old equipment_id name,
causing the test suite to surface Ecto.ConstraintError instead of a
changeset error. Required to get the suite green for this upgrade.
2026-04-30 10:26:18 -05:00

100 lines
2.4 KiB
Markdown

# Workers
Use `Oban.Pro.Worker` with `args_schema` for type-safe, validated job arguments:
```elixir
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`:
```elixir
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
```
## Encrypted jobs
Protect sensitive args with transparent encryption:
```elixir
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 creation
- `before_process/1` — runs before `process/1`
- `after_process/3` — runs after `process/1` with 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
```elixir
@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:
```elixir
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:
```elixir
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]
```