Current section

Files

Jump to
oban lib oban queue drainer.ex
Raw

lib/oban/queue/drainer.ex

defmodule Oban.Queue.Drainer do
@moduledoc false
import Ecto.Query, only: [where: 3]
alias Oban.{Config, Job, Repo}
alias Oban.Queue.Executor
@infinite 100_000_000
def drain(%Config{} = conf, [_ | _] = opts) do
args =
opts
|> Map.new()
|> Map.put_new(:with_limit, @infinite)
|> Map.put_new(:with_recursion, false)
|> Map.put_new(:with_safety, true)
|> Map.put_new(:with_scheduled, false)
|> Map.update!(:queue, &to_string/1)
drain(conf, %{cancelled: 0, discard: 0, failure: 0, snoozed: 0, success: 0}, args)
end
defp stage_scheduled(conf, queue, with_scheduled) do
query =
Job
|> where([j], j.state in ["scheduled", "retryable"])
|> where([j], j.queue == ^queue)
query =
case with_scheduled do
true -> query
%DateTime{} -> where(query, [j], j.scheduled_at <= ^with_scheduled)
end
Repo.update_all(conf, query, set: [state: "available"])
end
defp drain(conf, old_acc, %{queue: queue} = args) do
if args.with_scheduled, do: stage_scheduled(conf, queue, args.with_scheduled)
new_acc =
conf
|> fetch_available(args)
|> Enum.reduce(old_acc, fn job, acc ->
result =
conf
|> Executor.new(job, safe: args.with_safety)
|> Executor.call()
|> case do
%{state: :exhausted} -> :discard
%{state: state} -> state
end
Map.update(acc, result, 1, &(&1 + 1))
end)
if args.with_recursion and old_acc != new_acc do
drain(conf, new_acc, args)
else
new_acc
end
end
defp fetch_available(conf, %{queue: queue, with_limit: limit}) do
{:ok, meta} = conf.engine.init(conf, queue: queue, limit: limit)
{:ok, {_meta, jobs}} = conf.engine.fetch_jobs(conf, meta, %{})
jobs
end
end