Skip to content

Instantly share code, notes, and snippets.

@art-solopov
Created September 13, 2019 18:19
Show Gist options
  • Save art-solopov/4925b8f46a288167fe6c7664dabfdbfd to your computer and use it in GitHub Desktop.
Save art-solopov/4925b8f46a288167fe6c7664dabfdbfd to your computer and use it in GitHub Desktop.
Playing with Elixir supervisors
defmodule ElxSupPlay.Server do
use GenServer
def start_link({parent_sup, workers_count = 8}) do
GenServer.start_link(__MODULE__, {parent_sup, workers_count}, name: __MODULE__)
end
def report do
GenServer.call(__MODULE__, :report)
end
def register_worker(pid), do: GenServer.cast(__MODULE__, {:register_worker, pid})
# Callbacks
def init({parent_sup, workers_count}) do
GenServer.cast(__MODULE__, {:start_worker_sup, workers_count})
{:ok, {parent_sup, :none, []}}
end
def handle_cast({:start_worker_sup, workers_count}, {parent_sup, :none, []}) do
{:ok, workers_sup} = Supervisor.start_child(parent_sup, {ElxSupPlay.WorkerSupervisor, nil})
(1..workers_count)
|> Enum.each(fn (_) -> Supervisor.start_child(workers_sup, []) end)
{:noreply, {parent_sup, workers_sup, []}}
end
def handle_cast({:register_worker, pid}, {_, _, workers} = state) when is_pid(pid) do
Process.monitor(pid)
{:noreply, put_elem(state, 2, [pid | workers])}
end
def handle_call(:report, _from, state) do
{:reply, state, state}
end
def handle_info({:DOWN, _ref, :process, pid, _reason}, {psup, workers_sup, workers}) do
{:noreply, {psup, workers_sup, List.delete(workers, pid)}}
end
end
defmodule ElxSupPlay.Worker do
use GenServer
# API
def start_link(number) do
GenServer.start_link(__MODULE__, number)
end
# Callbacks
def init(start_num) do
ElxSupPlay.Server.register_worker(self())
{:ok, %{num: start_num}}
end
def handle_cast(:inc, %{num: num} = state) do
{:noreply, %{state | num: num + 1}}
end
def handle_cast(:dec, %{num: num} = state) do
{:noreply, %{state | num: num - 1}}
end
end
defmodule ElxSupPlay.WorkerSupervisor do
use Supervisor
# API
def start_link(_opts) do
Supervisor.start_link(__MODULE__, :ok)
end
# Callbacks
def init(:ok) do
children = [{ElxSupPlay.Worker, 0}]
opts = [
strategy: :simple_one_for_one,
max_restarts: 5,
max_seconds: 5
]
Supervisor.init(children, opts)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment