Packages

This package contains the templates of dynamic multi GenServer (aka. RequestBroker) and similaly dynamic multi queue and its crawler which has configurerable schedule to dequeue handler. We can help to implement such as RPC messaging subsystem.

Current section

Files

Jump to
rpcsdk lib rpcsdk queue.ex
Raw

lib/rpcsdk/queue.ex

defmodule Rpcsdk.Queue do
defmacro __using__(opts) do
supervisor_m = Keyword.get(opts, :supervisor_m, DynamicSupervisor)
registry_m = Keyword.get(opts, :registry_m, Registry)
supervisor = Keyword.get(opts, :supervisor)
registry = Keyword.get(opts, :registry)
crawler = Keyword.get(opts, :crawler)
quote do
use GenServer
# Helper APIs
def start_link(args) do
opts = args |> Keyword.take([:name])
GenServer.start_link(__MODULE__, [], opts)
end
def enqueue(nil, value), do: :ok
def enqueue(key, value) do
case unquote(registry_m).lookup(unquote(registry), queue_name(key)) do
[{pid, _}] ->
pid
_ ->
queue_spec = [name: queue_process(key)]
|> __MODULE__.child_spec()
pid = unquote(supervisor_m).start_child(unquote(supervisor), queue_spec)
|> case do
{:ok, x} ->
x
{:error, {:already_started, x}} ->
x
end
crawler_spec = [name: crawler_process(key), key: key]
|> unquote(crawler).child_spec()
unquote(supervisor_m).start_child(unquote(supervisor), crawler_spec)
pid
end
|> GenServer.cast({:enqueue, value})
end
def dequeue(key) do
try do
queue_process(key)
|> GenServer.call(:dequeue)
catch
:exit, _ -> nil
end
end
def queue(key) do
try do
queue_process(key)
|> GenServer.call(:queue)
catch
:exit, _ -> []
end
end
def terminate(key) do
with [{pid, _}] <- unquote(registry_m).lookup(unquote(registry),
crawler_name(key)) do
unquote(supervisor_m).terminate_child(unquote(supervisor), pid)
end
with [{pid, _}] <- unquote(registry_m).lookup(unquote(registry),
queue_name(key)) do
unquote(supervisor_m).terminate_child(unquote(supervisor), pid)
end
end
def crawl(key) do
with [{pid, _}] <- unquote(registry_m).lookup(unquote(registry),
crawler_name(key)) do
send(pid, :crawl)
end
end
# GenServer callbacks
@impl GenServer
def init(state \\ []), do: {:ok, state}
@impl GenServer
def handle_cast({:enqueue, value}, state), do: {:noreply, state ++ [value]}
@impl GenServer
def handle_call(:dequeue, _, [value | state]), do: {:reply, value, state}
def handle_call(:dequeue, _, []), do: {:reply, nil, []}
@impl GenServer
def handle_call(:queue, _, state), do: {:reply, state, state}
defp queue_process(key),
do: {:via, unquote(registry_m), {unquote(registry), queue_name(key)}}
defp crawler_process(key),
do: {:via, unquote(registry_m), {unquote(registry), crawler_name(key)}}
defp queue_name(key), do: "rpcsdk_queue_#{key}"
defp crawler_name(key), do: "rpcsdk_crawler_#{key}"
end
end
end