Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
defmodule Swarm.DynamicSupervisor do
use GenServer
require Logger
defstruct [
:child_name,
:child_module,
:child_args,
:group,
:pid,
:proc_name
]
def start_link(opts, proc_opts \\ []) do
GenServer.start_link(__MODULE__, {opts, proc_opts}, proc_opts)
end
def init({opts, proc_opts}) do
state = %__MODULE__{
child_name: Keyword.get(opts, :name),
child_module: Keyword.get(opts, :module),
child_args: Keyword.get(opts, :args, []),
group: Keyword.get(opts, :group, nil),
pid: nil,
proc_name: Keyword.get(proc_opts, :name, self())
}
register_swarm(state)
{:ok, state}
end
def register_swarm(state) do
Task.start_link(fn ->
case {Swarm.register_name(state.child_name, __MODULE__, :start_child, [state.proc_name]), state.group} do
{{:ok, pid}, group} when group != nil -> Swarm.join(group, pid)
{{:error, :already_registered}, _} -> :ok
{{:ok, pid}, nil} -> :ok
{{:error, error}, _} -> Logger.warn("Got error from Swarm.register_name: #{inspect error}")
end
end)
end
def start_child(pid) do
GenServer.call(pid, :start_child)
end
def handle_call(:start_child, _from, state) do
case apply(state.child_module, :start_link, state.child_args) do
{:ok, pid} ->
Process.monitor(pid)
Process.unlink(pid)
{:reply, {:ok, pid}, %{state | pid: pid}}
other ->
{:reply, other, state}
end
end
def handle_info({:DOWN, ref, :process, pid, reason}, %{pid: pid} = state) when not reason in [:normal, :shutdown] do
# restart that process here by calling register_swarm
register_swarm(state)
{:noreply, %{state | pid: nil}}
end
def terminate(reason, state) do
case state.pid do
nil -> :ok
pid -> Process.exit(pid, reason)
end
:shutdown
end
def handle_info(_other, state), do: {:noreply, state}
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment