Skip to content

Instantly share code, notes, and snippets.

@ostinelli
Last active August 11, 2022 17:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ostinelli/3638082d75ff5e0b44bae0d0a40f01f0 to your computer and use it in GitHub Desktop.
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)
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
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