Oban Background Jobs Reference
SkillAI & modelsOban job processing — workers, perform/1 (OSS) and process/1 (Pro), queues,
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Oban Background Jobs Reference skill
What this skill tells your AI
The instructions your AI receives, as published by oliver-kriska/claude-elixir-phoenix in targets/pi/skills/oban/SKILL.md and read by ahel’s review.
Quick reference for Elixir Oban patterns.
Oban Pro Detection
Before applying patterns, check for Oban Pro:
grep -E "oban_pro|oban_web" mix.exs
grep -r "use Oban.Pro.Worker" lib/
grep -r "Oban.Pro.Engines.Smart" config/
If Oban Pro detected, use Pro patterns for ALL new workers:
| Standard Oban | Oban Pro |
|---|---|
use Oban.Worker | use Oban.Pro.Worker |
def perform(%Job{}) | def process(%Job{}) |
Oban.Testing | Oban.Pro.Testing |
| Advisory lock engine | Oban.Pro.Engines.Smart |
Pro features (all optional): args_schema (typed args), Workflows, Batches, Chunks,
Relay, hooks, encryption, deadlines, chaining, Smart Engine (global concurrency + rate limiting).
Pro plugins (DynamicCron, DynamicLifeline, DynamicPruner) enhance OSS equivalents — swap module, don't run both.
See references/oban-pro-basics.md for all patterns and migration guide.
Iron Laws — Never Violate These
- JOBS MUST BE IDEMPOTENT — Safe to retry. Use idempotency keys for payments
- JOBS MUST STORE IDs, NOT STRUCTS — JSON serialization.
%{user_id: 1}not%{user: %User{}} - JOBS MUST HANDLE ALL RETURN VALUES —
:ok,{:error, _},{:cancel, _},{:snooze, _} - ARGS USE STRING KEYS — Pattern match
%{"user_id" => id}not%{user_id: id} - UNIQUE CONSTRAINTS FOR USER ACTIONS — Prevent double-click duplicates
- NEVER STORE LARGE DATA IN ARGS — Store references (IDs, paths), not content
- SMART ENGINE: NEVER USE
attemptTO LIMIT SNOOZES — Snooze rolls back attempt counter. Usemeta["snoozed"]instead. Causes infinite loops
Quick Worker Template
defmodule MyApp.Workers.ExampleWorker do
use Oban.Worker,
queue: :default,
max_attempts: 5,
unique: [period: {5, :minutes}, keys: [:entity_id]]
@impl Oban.Worker
def perform(%Oban.Job{args: %{"entity_id" => id}}) do
case process(id) do
{:ok, _} -> :ok
{:error, :not_found} -> {:cancel, "Entity not found"}
{:error, :rate_limited} -> {:snooze, {5, :minutes}}
{:error, reason} -> {:error, reason}
end
end
end
Return Value Meanings
| Return | State | Behavior |
|---|---|---|
:ok | completed | Success |
{:ok, value} | completed | Success with value |
{:error, reason} | retryable | Retry with backoff |
{:cancel, reason} | cancelled | Stop permanently |
{:snooze, seconds} | scheduled | Delay and retry |
Quick Decisions
Which Queue?
- Critical operations → High concurrency (20+)
- Mailers/Webhooks (I/O) → Medium concurrency (30-50)
- CPU-intensive → Low concurrency (3-5)
- External APIs → Use
dispatch_cooldownfor rate limiting
Testing Pattern
use Oban.Testing, repo: MyApp.Repo
# Assert enqueued
assert_enqueued worker: MyApp.Worker, args: %{id: 1}
# Execute and verify
assert :ok = perform_job(MyApp.Worker, %{id: 1})
Common Anti-patterns
| Wrong | Right |
|---|---|
%{user_id: id} pattern match | %{"user_id" => id} (string keys) |
%{user: %User{}} in args | %{user_id: 1} (IDs only) |
| No idempotency for payments | Use idempotency keys |
| Ignoring return values | Handle all outcomes explicitly |
References
For detailed patterns, see:
references/worker-patterns.md- Worker options, backoff, timeoutreferences/queue-config.md- Queue design, pool sizing, cron, Smart Enginereferences/testing-patterns.md- Testing, assertions, drain (OSS + Pro)references/oban-pro-basics.md- Pro.Worker, Workflow, Batch, Chunk, Relay, plugins
Signals
- GitHub stars
- 543
- Forks
- 38
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
oban- Source
- github.com/oliver-kriska/claude-elixir-phoenix