Packages
oban
2.17.6
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/peer.ex
defmodule Oban.Peer do
@moduledoc """
The `Peer` module maintains leadership for a particular Oban instance within a cluster.
Leadership is used by plugins, primarily, to prevent duplicate work across nodes. For example,
only the leader's `Cron` plugin will try inserting new jobs. You can use peer leadership to
extend Oban with custom plugins, or even within your own application.
Note a few important details about how peer leadership operates:
* Each peer checks for leadership at a 30 second interval. When the leader exits it broadcasts a
message to all other peers to encourage another one to assume leadership.
* Each Oban instance supervises a distinct `Oban.Peer` instance. That means that with multiple
Oban instances on the same node one instance may be the leader, while the others aren't.
* Without leadership, global plugins (Cron, Lifeline, Stager, etc.), will not run on any node.
## Available Peer Implementations
There are two built-in peering modules:
* `Oban.Peers.Postgres` — uses table-based leadership through the `oban_peers` table and works
in any environment, with or without clustering. Only one node (per instance name) will have a
row in the peers table, that node is the leader. This is the default.
* `Oban.Peers.Global` — coordinates global locks through distributed Erlang, requires
distributed Erlang.
You can specify the peering module to use in your Oban configuration:
config :my_app, Oban,
peer: Oban.Peers.Postgres, # default value
...
If in doubt, you can call `Oban.config()` to see which module is being used.
## Examples
Check leadership for the default Oban instance:
Oban.Peer.leader?()
# => true
That is identical to using the name `Oban`:
Oban.Peer.leader?(Oban)
# => true
Check leadership for a couple of instances:
Oban.Peer.leader?(Oban.A)
# => true
Oban.Peer.leader?(Oban.B)
# => false
"""
alias Oban.{Config, Registry}
require Logger
@type option ::
{:name, module()}
| {:conf, Config.t()}
| {:interval, timeout()}
@doc """
Starts a peer instance.
"""
@callback start_link([option()]) :: GenServer.on_start()
@doc """
Check whether the current peer instance leads the cluster.
"""
@callback leader?(Config.t() | GenServer.server()) :: boolean()
@doc false
@spec child_spec(Keyword.t()) :: Supervisor.child_spec()
def child_spec(opts) do
%{peer: {peer, peer_opts}} = Keyword.fetch!(opts, :conf)
opts =
opts
|> Keyword.merge(peer_opts)
|> Keyword.put_new(:name, peer)
%{id: opts[:name], start: {peer, :start_link, [opts]}}
end
@doc """
Check whether the current instance leads the cluster.
## Example
Check leadership for the default Oban instance:
Oban.Peer.leader?()
# => true
Check leadership for an alternate instance named `Oban.Private`:
Oban.Peer.leader?(Oban.Private)
# => true
"""
@spec leader?(Config.t() | GenServer.server()) :: boolean()
def leader?(conf_or_name \\ Oban, timeout \\ 5_000)
def leader?(%Config{name: name, peer: {peer, _}}, timeout) do
case Registry.whereis(name, Oban.Peer) do
pid when is_pid(pid) ->
peer.leader?(pid, timeout)
nil ->
false
end
catch
:exit, {:timeout, _} = reason ->
Logger.warning("Oban.Peer.leader?/2 check failed due to #{inspect(reason)}.")
false
end
def leader?(name, timeout) do
name
|> Oban.config()
|> leader?(timeout)
end
end