Packages
oban
2.16.2
2.23.0
2.22.1
2.22.0
2.21.1
2.21.0
2.20.3
2.20.2
2.20.1
2.20.0
2.19.4
2.19.3
2.19.2
2.19.1
2.19.0
2.18.3
2.18.2
2.18.1
2.18.0
2.17.12
2.17.11
2.17.10
2.17.9
2.17.8
2.17.7
2.17.6
2.17.5
2.17.4
2.17.3
2.17.2
2.17.1
2.17.0
2.16.3
2.16.2
2.16.1
2.16.0
2.15.4
2.15.3
2.15.2
2.15.1
2.15.0
2.14.2
2.14.1
2.14.0
2.13.6
2.13.5
2.13.4
2.13.3
2.13.2
2.13.1
2.13.0
2.12.1
2.12.0
2.11.3
2.11.2
2.11.1
2.11.0
2.10.1
2.10.0
retired
2.9.2
2.9.1
2.9.0
2.8.0
2.7.2
2.7.1
2.7.0
2.6.1
2.6.0
2.5.0
2.4.3
2.4.2
2.4.1
2.4.0
2.3.4
2.3.3
2.3.2
2.3.1
2.3.0
2.2.0
2.1.0
2.0.0
2.0.0-rc.3
2.0.0-rc.2
2.0.0-rc.1
2.0.0-rc.0
1.2.0
1.1.0
1.0.0
1.0.0-rc.2
1.0.0-rc.1
0.12.1
0.12.0
0.11.1
0.11.0
0.10.1
0.10.0
0.9.0
0.8.1
0.8.0
0.7.1
0.7.0
0.6.0
0.5.0
0.4.0
0.3.0
0.2.0
0.1.0
Robust job processing, backed by modern PostgreSQL, SQLite3, and MySQL.
Current section
Files
Jump to
Current section
Files
lib/oban/repo.ex
defmodule Oban.Repo do
@moduledoc """
Wrappers around `Ecto.Repo` and `Ecto.Adapters.SQL` callbacks.
Each function resolves the correct repo instance and sets options such as `prefix` and `log`
according to `Oban.Config`.
> #### Meant for Extending Oban {: .warning}
>
> These functions should only be used when working with a repo inside engines, plugins, or other
> extensions for Oban. Favor using your application's repo directly when querying `Oban.Job`
> from your workers.
## Examples
The first argument for every function must be an `Oban.Config` struct. Many functions pass
configuration around as a `conf` key, and it can always be fetched with `Oban.config/1`. This
demonstrates fetching the default instance config and querying all jobs:
Oban
|> Oban.config()
|> Oban.Repo.all(Oban.Job)
"""
@moduledoc since: "2.2.0"
alias Oban.Config
@callbacks_without_opts [
config: 0,
default_options: 1,
get_dynamic_repo: 0,
in_transaction?: 0,
load: 2,
put_dynamic_repo: 1,
rollback: 1
]
@callbacks_with_opts [
aggregate: 3,
all: 2,
checkout: 2,
delete!: 2,
delete: 2,
delete_all: 2,
exists?: 2,
get!: 3,
get: 3,
get_by!: 3,
get_by: 3,
insert!: 2,
insert: 2,
insert_all: 3,
insert_or_update!: 2,
insert_or_update: 2,
one!: 2,
one: 2,
preload: 3,
reload!: 2,
reload: 2,
stream: 2,
transaction: 2,
update!: 2,
update: 2,
update_all: 3
]
for {fun, arity} <- @callbacks_without_opts do
args = [Macro.var(:conf, __MODULE__) | Macro.generate_arguments(arity, __MODULE__)]
@doc """
Wraps `c:Ecto.Repo.#{fun}/#{arity}` with an additional `Oban.Config` argument.
"""
def unquote(fun)(unquote_splicing(args)) do
__dispatch__(unquote(fun), unquote(args))
end
end
for {fun, arity} <- @callbacks_with_opts do
args = [Macro.var(:conf, __MODULE__) | Macro.generate_arguments(arity - 1, __MODULE__)]
@doc """
Wraps `c:Ecto.Repo.#{fun}/#{arity}` with an additional `Oban.Config` argument.
"""
def unquote(fun)(unquote_splicing(args), opts \\ []) do
__dispatch__(unquote(fun), unquote(args), opts)
end
end
# Manually Defined
@doc """
The default values extracted from `Oban.Config` for use in all queries with options.
"""
@doc since: "2.14.0"
def default_options(conf) do
base = [log: conf.log, oban: true, telemetry_options: [oban_conf: conf]]
if conf.prefix do
[prefix: conf.prefix] ++ base
else
base
end
end
@doc """
Wraps `Ecto.Adapters.SQL.Repo.query/4` with an added `Oban.Config` argument.
"""
@doc since: "2.2.0"
def query(conf, statement, params \\ [], opts \\ []) do
__dispatch__(:query, [conf, statement, params], opts)
end
@doc """
Wraps `Ecto.Adapters.SQL.Repo.to_sql/2` with an added `Oban.Config` argument.
"""
@doc since: "2.2.0"
def to_sql(conf, kind, queryable) do
query =
queryable
|> Ecto.Queryable.to_query()
|> Map.put(:prefix, conf.prefix)
conf.repo.to_sql(kind, query)
end
defp __dispatch__(name, [%Config{} = conf | args]) do
with_dynamic_repo(conf, name, args)
end
defp __dispatch__(name, [%Config{} = conf | args], opts) when is_list(opts) do
opts =
conf
|> default_options()
|> Keyword.merge(opts)
with_dynamic_repo(conf, name, args ++ [opts])
end
defp with_dynamic_repo(%{get_dynamic_repo: fun} = conf, name, args) when is_function(fun, 0) do
prev_instance = conf.repo.get_dynamic_repo()
try do
unless in_transaction?(conf, prev_instance) do
conf.repo.put_dynamic_repo(fun.())
end
apply(conf.repo, name, args)
after
conf.repo.put_dynamic_repo(prev_instance)
end
end
defp with_dynamic_repo(conf, name, args) do
apply(conf.repo, name, args)
end
defp in_transaction?(conf, instance) when is_pid(instance), do: conf.repo.in_transaction?()
defp in_transaction?(conf, instance) when is_atom(instance) do
case GenServer.whereis(instance) do
pid when is_pid(pid) -> in_transaction?(conf, pid)
_ -> false
end
end
defp in_transaction?(_, _), do: false
end