Background
I am reading the “Functional Web Development with Elixir, OTP and Phoenix” book, and I finished a Supervisor that supervises Games. Games can start and end so this is in reality a DynamicSupervisor, but when the book was written the strategy :simple_one_for_one
was still not deprecated and so that is what they used.
My objective is to replace the deprecated Supervisor with a Dynamic one and get rid of the deprecation warnings.
Code
Following is the (deprecated) Supervisor the book gives (I added specs):
defmodule IslandsEngine.GameSupervisor do
use Supervisor
alias IslandsEngine.Game
@spec start_link(any) :: Supervisor.on_start
def start_link(_args), do:
Supervisor.start_link(__MODULE__, :ok, name: __MODULE__)
@spec start_game(String.t) :: Supervisor.on_start_child
def start_game(name), do:
Supervisor.start_child(__MODULE__, [name])
@spec stop_game(String.t) :: :ok | {:error, :not_found | :simple_one_for_one}
def stop_game(name) do
:ets.delete(:game_state, name)
Supervisor.terminate_child(__MODULE__, pid_from_name(name))
end
@impl Supervisor
@spec init(:ok) :: {:ok, tuple}
def init(:ok), do:
Supervisor.init([Game], strategy: :simple_one_for_one)
defp pid_from_name(name) do
name
|> Game.via_tuple()
|> GenServer.whereis()
end
end
This code works, but makes Dyalizer go crazy. Furthermore, the strategy used here is also deprecated.
This is my attempt at upgrading this code:
defmodule IslandsEngine.GameSupervisor do
use DynamicSupervisor
alias IslandsEngine.Game
@spec start_link(any) :: DynamicSupervisor.on_start
def start_link(_args), do:
DynamicSupervisor.start_link(__MODULE__, :ok, name: __MODULE__)
@spec start_game(String.t) :: DynamicSupervisor.on_start_child
def start_game(name), do:
DynamicSupervisor.start_child(__MODULE__, {Game, [name]})
@spec stop_game(String.t) :: :ok | {:error, :not_found}
def stop_game(name) do
:ets.delete(:game_state, name)
DynamicSupervisor.terminate_child(__MODULE__, pid_from_name(name))
end
@impl DynamicSupervisor
@spec init(:ok) :: {:ok, DynamicSupervisor.sup_flags}
def init(:ok), do:
DynamicSupervisor.init(strategy: :one_for_one)
defp pid_from_name(name) do
name
|> Game.via_tuple()
|> GenServer.whereis()
end
end
Problem
However, when I run my version of the DynamicSupervisor I get the following error:
IslandsEngine.GameSupervisor.start_game("Fred")
{:error,
{:undef,
[
{IslandsEngine.Game, :start_link, [], []},
{DynamicSupervisor, :start_child, 3,
[file: 'lib/dynamic_supervisor.ex', line: 690]},
{DynamicSupervisor, :handle_start_child, 2,
[file: 'lib/dynamic_supervisor.ex', line: 676]},
{:gen_server, :try_handle_call, 4, [file: 'gen_server.erl', line: 661]},
{:gen_server, :handle_msg, 6, [file: 'gen_server.erl', line: 690]},
{:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 249]}
]}}
The deprecated version works just fine.
Questions
What am I doing wrong? Why are the two Supervisors not equivalent?