Design and implement Oban background job workers for Elixir. Configure queues, retry strategies, uniqueness constraints, cron scheduling, and error handling. Generate Oban workers, queue config, and test setups. Use when adding background jobs, async processing, scheduled tasks, or recurring cron jobs to an Elixir project using Oban.
数据来源:ClawHub。 在 ClawSkills 查看
选择你使用的 Agent
方法一:命令行安装(推荐)
推荐(无需提前安装 clawhub)
npx clawhub@latest --dir ~/.claude/skills install oban-designer或使用 clawhub CLI(需提前安装)
clawhub --dir ~/.claude/skills install oban-designer⚠️ 需要 Node.js 18+,没有 Node?请使用下方方法二直接下载 ZIP。 安装 Node.js →
方法二:手动下载安装(无需 Node)
下载 ZIP,解压后将文件夹放到以下路径,重启 Agent 即可:
安装路径
~/.claude/skills/oban-designer/💡解压后将文件夹放到上方路径,重启 Agent 即可生效
--- name: oban-designer description: "Design and implement Oban background job workers for Elixir. Configure queues, retry strategies, uniqueness constraints, cron scheduling, and error handling. Generate Oban workers, queue config, and test setups. Use when adding background jobs, async processing, scheduled tasks, or recurring cron jobs to an Elixir project using Oban." ---
# mix.exs
{:oban, "~> 2.18"}
# config/config.exs
config :my_app, Oban,
repo: MyApp.Repo,
queues: [default: 10, mailers: 20, webhooks: 50, events: 5],
plugins: [
Oban.Plugins.Pruner,
{Oban.Plugins.Cron, crontab: [
{"0 2 * * *", MyApp.Workers.DailyCleanup},
{"*/5 * * * *", MyApp.Workers.MetricsCollector}
]}
]
# In application.ex children:
{Oban, Application.fetch_env!(:my_app, Oban)}
Generate the Oban migrations:
mix ecto.gen.migration add_oban_jobs_table
defmodule MyApp.Repo.Migrations.AddObanJobsTable do
use Ecto.Migration
def up, do: Oban.Migration.up(version: 12)
def down, do: Oban.Migration.down(version: 1)
end
defmodule MyApp.Workers.SendEmail do
use Oban.Worker,
queue: :mailers,
max_attempts: 5,
priority: 1
@impl Oban.Worker
def perform(%Oban.Job{args: %{"to" => to, "template" => template} = args}) do
case MyApp.Mailer.deliver(to, template, args) do
{:ok, _} -> :ok
{:error, :temporary} -> {:error, "temporary failure"} # Will retry
{:error, :permanent} -> {:cancel, "invalid address"} # Won't retry
end
end
end
| Return | Effect | |--------|--------| | :ok | Job marked complete | | {:ok, result} | Job marked complete | | {:error, reason} | Job retried (counts as attempt) | | {:cancel, reason} | Job cancelled, no more retries | | {:snooze, seconds} | Re-scheduled, doesn't count as attempt | | {:discard, reason} | Job discarded (Oban 2.17+) |
See references/worker-patterns.md for common worker patterns.
| Queue | Concurrency | Use Case | |-------|------------|----------| | default | 10 | General-purpose | | mailers | 20 | Email delivery (I/O bound) | | webhooks | 50 | Webhook delivery (I/O bound, high volume) | | media | 5 | Image/video processing (CPU bound) | | events | 5 | Analytics, audit logs | | critical | 3 | Billing, payments |
Jobs within a queue execute by priority (0 = highest). Use sparingly:
%{user_id: user.id}
|> MyApp.Workers.SendEmail.new(priority: 0) # Urgent
|> Oban.insert()
Oban uses exponential backoff: attempt^4 + attempt seconds.
defmodule MyApp.Workers.WebhookDelivery do
use Oban.Worker,
queue: :webhooks,
max_attempts: 10
@impl Oban.Worker
def backoff(%Oban.Job{attempt: attempt}) do
# Exponential with jitter: 2^attempt + random(0..30)
trunc(:math.pow(2, attempt)) + :rand.uniform(30)
end
@impl Oban.Worker
def perform(%Oban.Job{args: args}) do
# ...
end
end
use Oban.Worker, queue: :media
@impl Oban.Worker
def timeout(%Oban.Job{args: %{"size" => "large"}}), do: :timer.minutes(10)
def timeout(_job), do: :timer.minutes(2)
Prevent duplicate jobs:
defmodule MyApp.Workers.SyncAccount do
use Oban.Worker,
queue: :default,
unique: [
period: 300, # 5 minutes
states: [:available, :scheduled, :executing, :retryable],
keys: [:account_id] # Unique by this arg key
]
end
| Option | Default | Description | |--------|---------|-------------| | period | 60 | Seconds to enforce uniqueness (:infinity for forever) | | states | all active | Which job states to check | | keys | all args | Specific arg keys to compare | | timestamp | :inserted_at | Use :scheduled_at for scheduled uniqueness |
%{account_id: id}
|> MyApp.Workers.SyncAccount.new(
replace: [:scheduled_at], # Update scheduled_at if duplicate
schedule_in: 60
)
|> Oban.insert()
# config.exs
plugins: [
{Oban.Plugins.Cron, crontab: [
{"0 */6 * * *", MyApp.Workers.DigestEmail},
{"0 2 * * *", MyApp.Workers.DailyCleanup},
{"0 0 1 * *", MyApp.Workers.MonthlyReport},
{"*/5 * * * *", MyApp.Workers.HealthCheck, args: %{service: "api"}},
]}
]
Cron expressions: minute hour day_of_month month day_of_week.
# Immediate
%{user_id: user.id, template: "welcome"}
|> MyApp.Workers.SendEmail.new()
|> Oban.insert()
# Scheduled
%{report_id: id}
|> MyApp.Workers.GenerateReport.new(schedule_in: 3600)
|> Oban.insert()
# Scheduled at specific time
%{report_id: id}
|> MyApp.Workers.GenerateReport.new(scheduled_at: ~U[2024-01-01 00:00:00Z])
|> Oban.insert()
# Bulk insert
changesets = Enum.map(users, fn user ->
MyApp.Workers.SendEmail.new(%{user_id: user.id})
end)
Oban.insert_all(changesets)
# Inside Ecto.Multi
Ecto.Multi.new()
|> Ecto.Multi.insert(:user, changeset)
|> Oban.insert(:welcome_email, fn %{user: user} ->
MyApp.Workers.SendEmail.new(%{user_id: user.id})
end)
|> Repo.transaction()
Available with Oban Pro license:
# Process items in batch, run callback when all complete
batch = MyApp.Workers.ProcessItem.new_batch(
items |> Enum.map(&%{item_id: &1.id}),
callback: {MyApp.Workers.BatchComplete, %{batch_name: "import"}}
)
Oban.insert_all(batch)
Oban.Pro.Workflow.new()
|> Oban.Pro.Workflow.add(:extract, MyApp.Workers.Extract.new(%{file: path}))
|> Oban.Pro.Workflow.add(:transform, MyApp.Workers.Transform.new(%{}), deps: [:extract])
|> Oban.Pro.Workflow.add(:load, MyApp.Workers.Load.new(%{}), deps: [:transform])
|> Oban.insert_all()
defmodule MyApp.Workers.BulkIndex do
use Oban.Pro.Workers.Chunk,
queue: :indexing,
size: 100, # Process 100 at a time
timeout: 30_000 # Or after 30s
@impl true
def process(jobs) do
items = Enum.map(jobs, & &1.args)
SearchIndex.bulk_upsert(items)
:ok
end
end
See references/testing-oban.md for detailed testing patterns.
# config/test.exs
config :my_app, Oban,
testing: :manual # or :inline for synchronous execution
# test_helper.exs (if using :manual)
Oban.Testing.start()
use Oban.Testing, repo: MyApp.Repo
test "enqueues welcome email on signup" do
{:ok, user} = Accounts.register(%{email: "[email protected]"})
assert_enqueued worker: MyApp.Workers.SendEmail,
args: %{user_id: user.id, template: "welcome"},
queue: :mailers
end
test "processes email delivery" do
{:ok, _} =
perform_job(MyApp.Workers.SendEmail, %{
"to" => "[email protected]",
"template" => "welcome"
})
end
# Attach in application.ex
:telemetry.attach_many("oban-logger", [
[:oban, :job, :start],
[:oban, :job, :stop],
[:oban, :job, :exception]
], &MyApp.ObanTelemetry.handle_event/4, %{})
安装 Oban Designer 后,可以对 AI 说这些话来触发它
Help me get started with Oban Designer
Explains what Oban Designer does, walks through the setup, and runs a quick demo based on your current project
Use Oban Designer to design and implement Oban background job workers for Elixir
Invokes Oban Designer with the right parameters and returns the result directly in the conversation
What can I do with Oban Designer in my marketing & growth workflow?
Lists the top use cases for Oban Designer, with example commands for each scenario
将技能文件夹放到 ~/.claude/skills/oban-designer/ 目录(个人级,所有项目可用),或 .claude/skills/oban-designer/(项目级)。重启 AI 客户端后,用 /oban-designer 主动调用,或让 AI 根据上下文自动发现并使用。
Oban Designer 支持 Claude、Cursor、OpenClaw,可与这些 AI 平台无缝集成,扩展其能力。
Oban Designer 可免费安装使用。请查阅仓库了解许可证信息。
Design and implement Oban background job workers for Elixir. Configure queues, retry strategies, uniqueness constraints, cron scheduling, and error handling. Generate Oban workers, queue config, and test setups. Use when adding background jobs, async processing, scheduled tasks, or recurring cron jobs to an Elixir project using Oban.
Oban Designer 属于「Marketing & Growth」分类,该分类的技能帮助 AI 智能体在此领域执行专业任务。
Automate my marketing & growth tasks using Oban Designer
Identifies repetitive steps in your workflow and sets up Oban Designer to handle them automatically