plugins/elixir-phoenix/skills/oban/SKILL.md
Oban job processing — workers, perform/1 (OSS) and process/1 (Pro), queues, cron, retries, unique jobs, idempotency, Oban Pro (Workflow, Batch, Chunk, Smart Engine), Testing. Use when writing Oban workers, queue config, or debugging jobs.
npx skillsauth add oliver-kriska/claude-elixir-phoenix obanInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Quick reference for Elixir Oban patterns.
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 ${CLAUDE_SKILL_DIR}/references/oban-pro-basics.md for all patterns and migration guide.
%{user_id: 1} not %{user: %User{}}:ok, {:error, _}, {:cancel, _}, {:snooze, _}%{"user_id" => id} not %{user_id: id}attempt TO LIMIT SNOOZES — Snooze rolls back attempt counter. Use meta["snoozed"] instead. Causes infinite loopsdefmodule 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 | 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 |
dispatch_cooldown for rate limitinguse 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})
| 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 |
For detailed patterns, see:
${CLAUDE_SKILL_DIR}/references/worker-patterns.md - Worker options, backoff, timeout${CLAUDE_SKILL_DIR}/references/queue-config.md - Queue design, pool sizing, cron, Smart Engine${CLAUDE_SKILL_DIR}/references/testing-patterns.md - Testing, assertions, drain (OSS + Pro)${CLAUDE_SKILL_DIR}/references/oban-pro-basics.md - Pro.Worker, Workflow, Batch, Chunk, Relay, pluginsdevelopment
Verify Elixir/Phoenix changes — compile, format, and test in one loop. Use after implementation, before PRs, or after fixing bugs.
development
OTP/BEAM patterns and Elixir idioms — GenServer, Supervisor, Task, Registry, pattern matching, with chains, pipes. Use when designing processes or debugging BEAM issues.
tools
Self-improving loop for plugin skills. Reads program.md, proposes one mutation per iteration, evaluates against deterministic scorer, keeps improvements via git, reverts failures. Targets weakest skill+dimension. Use with /loop for overnight runs.
development
Project health audit and health check — architecture, performance, tests, dependencies, code quality. Use when assessing overall project health, before releases, or after refactors.