Current section
Files
Jump to
Current section
Files
lib/rbmq/genqueue.ex
defmodule RBMQ.GenQueue do
@moduledoc false
@doc false
defmacro __using__(opts) do
quote bind_quoted: [opts: opts] do
use GenServer
use Confex, Keyword.delete(opts, :connection)
require Logger
@connection Keyword.get(opts, :connection) || @module_config[:connection]
@channel_name String.to_atom("#{__MODULE__}.Channel")
unless @connection do
raise "You need to implement connection module and pass it in :connection option."
end
def start_link do
GenServer.start_link(__MODULE__, config(), name: __MODULE__)
end
def init(opts) do
case Process.whereis(@connection) do
nil ->
# Connection doesn't exist, lets fail to recover later
{:error, :noconn}
_ ->
@connection.spawn_channel(@channel_name)
@connection.configure_channel(@channel_name, opts)
chan = get_channel()
|> init_worker(opts)
{:ok, chan}
end
end
def init_worker(chan, _opts) do
chan
end
def validate_config(conf) do
unless conf[:queue] do
raise "You need to configure queue in #{__MODULE__} options."
end
unless conf[:queue][:name] do
raise "You need to set queue name in #{__MODULE__} options."
end
case conf[:queue][:name] do
{:system, _, _} -> :ok
{:system, _} -> :ok
str when is_binary(str) -> :ok
unknown -> raise "Queue name for #{__MODULE__} must be a string or env link, '#{inspect unknown}' given."
end
conf
|> validate_config!
end
def validate_config!(conf) do
conf
end
defp get_channel do
chan = @channel_name
|> @connection.get_channel
end
def status do
GenServer.call(__MODULE__, :status)
end
def chan_config do
RBMQ.Connection.Channel.get_config(@channel_name)
end
def handle_call(:status, _from, chan) do
safe_run fn(_) ->
{:reply, AMQP.Queue.status(chan, chan_config()[:queue][:name]), chan}
end
end
def safe_run(fun) do
chan = get_channel()
case !is_nil(chan) && Process.alive?(chan.pid) do
true ->
fun.(chan)
_ ->
Logger.warn("[GenQueue] Channel #{inspect @channel_name} is dead, waiting till it gets restarted")
:timer.sleep(3_000)
safe_run(fun)
end
end
defoverridable [init_worker: 2, validate_config!: 1]
end
end
@doc """
Create a link to worker process. Used in supervisors.
"""
@callback start_link :: Supervisor.on_start
@doc """
Get queue status.
"""
@callback status :: {:ok, %{consumer_count: integer,
message_count: integer,
queue: String.t()}}
| {:error, String.t()}
end