lib/oban/registry.ex

defmodule Oban.Registry do
  @moduledoc """
  Local process storage for Oban instances.
  """

  @type role :: term()
  @type key :: Oban.name() | {Oban.name(), role()}
  @type value :: term()

  @doc false
  def child_spec(_arg) do
    [keys: :unique, name: __MODULE__]
    |> Registry.child_spec()
    |> Supervisor.child_spec(id: __MODULE__)
  end

  @doc """
  Fetch the config for an Oban supervisor instance.

  ## Example

  Get the default instance config:

      Oban.Registry.config(Oban)

  Get config for a custom named instance:

      Oban.Registry.config(MyApp.Oban)
  """
  @spec config(Oban.name()) :: Oban.Config.t()
  def config(oban_name) do
    case Registry.lookup(__MODULE__, oban_name) do
      [{_pid, config}] ->
        config

      _ ->
        raise RuntimeError,
              "no config registered for #{oban_name} instance, " <>
                "is the supervisor running?"
    end
  end

  @doc """
  Returns the pid of a supervised Oban process, or `nil` if the process can't be found.

  ## Example

  Get the Oban supervisor's pid:

      Oban.Registry.whereis(Oban)

  Get a supervised module's pid:

      Oban.Registry.whereis(Oban, Oban.Notifier)

  Get the pid for a plugin:

      Oban.Registry.whereis(Oban, {:plugin, MyApp.Oban.Plugin})

  Get the pid for a queue's producer:

      Oban.Registry.whereis(Oban, {:producer, :default})
  """
  @spec whereis(Oban.name(), role()) :: pid() | nil
  def whereis(oban_name, role \\ nil) do
    oban_name
    |> via(role)
    |> GenServer.whereis()
  end

  @doc """
  Build a via tuple suitable for calls to a supervised Oban process.

  ## Example

  For an Oban supervisor:

      Oban.Registry.via(Oban)

  For a supervised module:

      Oban.Registry.via(Oban, Oban.Notifier)

  For a plugin:

      Oban.Registry.via(Oban, {:plugin, Oban.Plugins.Cron})
  """
  @spec via(Oban.name(), role(), value()) :: {:via, Registry, {__MODULE__, key()}}
  def via(oban_name, role \\ nil, value \\ nil)
  def via(oban_name, role, nil), do: {:via, Registry, {__MODULE__, key(oban_name, role)}}
  def via(oban_name, role, value), do: {:via, Registry, {__MODULE__, key(oban_name, role), value}}

  defp key(oban_name, nil), do: oban_name
  defp key(oban_name, role), do: {oban_name, role}
end