Fl4m3Ph03n1x
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?
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixirconf-us
- #blog-post
- #ai
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming











Showing Posts 1 to 8- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
josevalim
From the stacktrace you can see that
Game.start_link/0is being called. But whystart_linkwith arity 0? The default should be to callstart_link(game_name), which is what you expect, UNLESS there is achild_spec/1function in the Game module (or an argument onuse GenServer) that is instructing it to pass no arguments toGame.start_link.Once you remove the custom
child_spec, everything should work.Fl4m3Ph03n1x
Indeed, according to the book this is the case. The thing I don’t understand is why the deprecated version works without changing the
Game.child_specbut the DynamicSupervisor version doesn’t.Are these 2 versions incompatible in a way I am missing here?
Chrichton
Unfortunately, the solution did not work for me. I removed the child_spec in use GenServer,
tried: IslandsEngine.GameSupervisor.start_game(“Fred”)
and got:
{:function_clause,
[
{IslandsEngine.Game, :start_link, [[“Fred”]],
[file: ‘lib/islands_engine/game.ex’, line: 27]},
{DynamicSupervisor, :start_child, 3,
[file: ‘lib/dynamic_supervisor.ex’, line: 692]},
{DynamicSupervisor, :handle_start_child, 2,
[file: ‘lib/dynamic_supervisor.ex’, line: 678]},
{:gen_server, :try_handle_call, 4, [file: ‘gen_server.erl’, line: 706]},
{:gen_server, :handle_msg, 6, [file: ‘gen_server.erl’, line: 735]},
{:proc_lib, :init_p_do_apply, 3, [file: ‘proc_lib.erl’, line: 226]}
]}}
I changed:
def start_game(name), do: DynamicSupervisor.start_child(MODULE, {Game, [name]})
to:
def start_game(name), do: DynamicSupervisor.start_child(MODULE, {Game, name})
and now everything works.
sotoseattle
I had the same issue. The thing that did the trick for me was how you define the spec:
spec = %{id: Game, start: {Game, :start_link, [name]}}So the whole GameSupervisor looks like this:
rm-rf-etc
This code doesn’t make sense to me,
start_gamedoesn’t callpid_from_name, butstop_gamedoes. It doesn’t look like the via_tuple is associated with the process at startup.Fl4m3Ph03n1x
Reading the book will help understand it. I recommend you have a look at the list of discounts the forum offers:
There might be other threads, I recommend you search for a few.
kigila
Hello, did you manage to sold the issue ?
I solved the start_game method, but the stop_game method is broken. pid_from_name method return nil always. Thats suckes considering I have been religiously following the book. I believe it is some problem with Registry but I have no clue what is wrong. Man I wish I had a ginie. ChatGPT says it cannot help.
kigila
In the application module include the GameSupervisor to the supervision tree like this:
In the game.ex module your GenServer.start_link should be called like this:
you can see that I wrap mine in a public method I called start_game( it beautiful this way)
And finally in the GameSupervisor module, here is how I defined the start_game module:
Maybe I have a ginie and dont know it. Hope that helps you. No soffer no more.