Last active
August 11, 2022 17:43
-
-
Save ostinelli/3638082d75ff5e0b44bae0d0a40f01f0 to your computer and use it in GitHub Desktop.
Elixir DynamicSupervisor with registered worker ids (local registry, use :syn for global workers instead)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule MyApp.Worker do | |
use GenServer | |
# api | |
@spec start_link(worker_id :: String.t()) :: GenServer.on_start() | |
def start_link(worker_id) do | |
GenServer.start_link(__MODULE__, [worker_id], name: via_tuple(worker_id)) | |
end | |
@spec child_spec([term()]) :: Supervisor.child_spec() | |
def child_spec([worker_id]) do | |
%{ | |
id: __MODULE__, | |
start: {__MODULE__, :start_link, [worker_id]}, | |
restart: :transient | |
} | |
end | |
@spec stop(worker_id :: String.t()) :: :ok | |
def stop(worker_id) do | |
# Given the :transient option in the child spec, the GenServer will restart | |
# if any reason other than `:normal` is given. | |
GenServer.stop(via_tuple(worker_id)) | |
end | |
@spec ping(worker_id :: String.t()) :: :pong | |
def ping(worker_id) do | |
GenServer.call(via_tuple(worker_id), :ping) | |
end | |
# callbacks | |
@impl true | |
def init([worker_id]) do | |
{:ok, %{id: worker_id}} | |
end | |
@impl true | |
def handle_call(:ping, _from, state) do | |
{:reply, :pong, state} | |
end | |
# internal | |
@spec via_tuple(worker_id :: String.t()) :: {:via, Registry, {:worker_registry, worker_id :: String.t()}} | |
defp via_tuple(worker_id), do: {:via, Registry, {:worker_registry, worker_id}} | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule MyApp.WorkerSupervisor do | |
@moduledoc """ | |
Ensure that the registry and the supervisor are started by adding them to a supervisor's children: | |
children = [ | |
... | |
{MyApp.WorkerSupervisor, []}, | |
{Registry, keys: :unique, name: :worker_registry}, | |
... | |
] | |
""" | |
use DynamicSupervisor | |
alias MyApp.Worker | |
# api | |
@spec start_link(term()) :: Supervisor.on_start() | |
def start_link(_arg) do | |
DynamicSupervisor.start_link(__MODULE__, [], name: __MODULE__) | |
end | |
@spec start_worker(worker_id :: String.t()) :: DynamicSupervisor.on_start_child() | |
def start_worker(worker_id) do | |
DynamicSupervisor.start_child(__MODULE__, {Worker, [worker_id]}) | |
end | |
# callbacks | |
@impl true | |
def init([]) do | |
DynamicSupervisor.init(strategy: :one_for_one) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment