如何让Oban任务执行频率超过每分钟一次?
解决Oban中Worker每10-30秒执行的需求
针对Cron插件无法支持高于每分钟执行频率的问题,以下两种非hack式方案均基于Oban原生能力实现,无需切换框架:
方案一:Worker自调度
让Worker在执行完成后自动调度下一次任务,通过随机间隔控制执行频率:
- 修改Worker实现,在
perform/1末尾添加调度逻辑:
defmodule MyApp.Workers.W1 do use Oban.Worker @impl true def perform(_args) do # 原有任务执行代码 # 生成10-30秒的随机间隔 schedule_in = :rand.uniform(21) + 10 # 插入下一次执行的任务 __MODULE__.new(%{}) |> Oban.insert(schedule_in: schedule_in) :ok end end
- 初始化触发:在应用启动时(比如
application.ex的启动回调中)手动插入一次初始任务,之后Worker会自动循环调度。
方案二:自定义调度插件
编写轻量的Oban插件,集中管理高频任务的调度:
- 实现自定义插件:
defmodule MyApp.Plugins.FrequentScheduler do use Oban.Plugin @impl true def start_link(opts) do GenServer.start_link(__MODULE__, opts, name: __MODULE__) end @impl true def init(opts) do workers = Keyword.get(opts, :workers, []) schedule_next_run(workers) {:ok, workers} end @impl true def handle_info(:schedule_jobs, workers) do # 批量插入指定Worker的任务 Enum.each(workers, fn worker -> worker.new(%{}) |> Oban.insert() end) # 随机10-30秒后触发下一次调度 schedule_in = :rand.uniform(21) + 10 schedule_next_run(workers, schedule_in) {:noreply, workers} end defp schedule_next_run(workers, schedule_in \\ 10) do Process.send_after(self(), :schedule_jobs, schedule_in * 1000) end end
- 在Oban配置中添加该插件:
# ..... {Oban.Plugins.Cron, crontab: [ # 保留原有Cron任务(如果需要) ]}, {MyApp.Plugins.FrequentScheduler, workers: [MyApp.Workers.W1, MyApp.Workers.W2]},
方案对比
- 自调度方案:每个Worker独立控制间隔,适合单Worker个性化调度场景,需手动触发初始任务。
- 自定义插件:集中管理所有高频任务,启动后自动运行,无需额外初始化操作。
内容的提问来源于stack exchange,提问作者Kon
相关产品推荐
相关产品推荐

