Registry, DynamicSupervisor & PartitionSupervisor

Duplicate-key registries act as local pub/sub:

34.1 DynamicSupervisor — start children on demand

children = [{DynamicSupervisor, name: MyApp.RoomSup, strategy: :one_for_one}]

{:ok, pid} = DynamicSupervisor.start_child(MyApp.RoomSup, {ChatRoom, "lobby"})
DynamicSupervisor.terminate_child(MyApp.RoomSup, pid)
DynamicSupervisor.which_children(MyApp.RoomSup)

34.2 Registry — local process registry (key → pid)

Duplicate-key registries act as local pub/sub:

{Registry, keys: :unique, name: MyApp.Registry}

defmodule ChatRoom do
  use GenServer
  def start_link(name), do: GenServer.start_link(__MODULE__, name, name: via(name))
  def via(name), do: {:via, Registry, {MyApp.Registry, name}}
  def say(room, msg), do: GenServer.cast(via(room), {:say, msg})
  @impl true
  def init(name), do: {:ok, %{name: name, messages: []}}
  @impl true
  def handle_cast({:say, m}, s), do: {:noreply, %{s | messages: [m | s.messages]}}
end

Registry.lookup(MyApp.Registry, "lobby")      # [{pid, value}]
{Registry, keys: :duplicate, name: MyApp.PubSub}
Registry.register(MyApp.PubSub, "topic", [])
Registry.dispatch(MyApp.PubSub, "topic", fn entries -> for {pid, _} <- entries, do: send(pid, :event) end)

34.3 PartitionSupervisor — scale a bottleneck

Starts N copies (default = schedulers) and routes by key.

{PartitionSupervisor, child_spec: DynamicSupervisor, name: MyApp.DynSups}
DynamicSupervisor.start_child({:via, PartitionSupervisor, {MyApp.DynSups, self()}}, spec)