3 ms·
> They are probably talking about the child spec needing a unique ID if it's the same module being started. No, my experience says that's not true. I have this
by simoncion 2y ago
> They are probably talking about the child spec needing a unique ID if it's the same module being started.
No, my experience says that's not true. I have this code in one of my projects and it works just fine:
-behavior(gen_server).
start(Mod, Args) ->
supervisor:start_child(secret_project_worker_sup:getName(), [{Mod, Args}]).
I can spawn as many of those guys as I like and they all become children of the named supervisor. The named supervisor is a 'simple_one_for_one' supervisor with a 'temporary' restart policy.
I guess the thing that might trip folks up with how the docs are worded is not noticing this further up in the document
A supervisor can have one of the following restart strategies specified with the strategy key in the above map:
...
* simple_one_for_one - A simplified one_for_one supervisor, where all child processes are dynamically added instances of the same process type, that is, running the same code.
and that 'start_child/2' accepts EITHER a 'child_spec()' OR a list of terms
-spec start_child(SupRef, ChildSpec) -> startchild_ret()
when SupRef :: sup_ref(), ChildSpec :: child_spec();
(SupRef, ExtraArgs) -> startchild_ret() when SupRef :: sup_ref(), ExtraArgs :: [term()].
and that only the 'child_spec()' type can have an identifier, so the first bullet point in the list of three in the function documentation does not apply.
Also, I find the way the docs USED to print out function types a bit easier to understand than the new style: <https://web.archive.org/web/20170509120825/http://erlang.org/doc/man/supervisor.html#start_child-2 https://web.archive.org/web/20170509120825/http://erlang.org...>. (You will need to either close the Archive.org nav banner or scroll up a line to see the first line of the function type information, which is pretty informative.)
- dqv 2y agoI'm talking about the behavior of the one_for_one supervisor: defmodule Testing.Application do use Application @impl Application def start(_type, _args) do children = [] opts = [strategy: :one_for_one, name: Testing.Supervisor] Supervisor.start_link(children, opts) end end defmodule Testing.Server do use GenServer def start_link(_), do: GenServer.start_link(__MODULE__, []) @impl GenServer def init(_), do: {:ok, nil} end When you try to start more than one child, it fails: Erlang/OTP 25 [erts-13.2.2.11] [source] [64-bit] [smp:14:14] [ds:14:14:10] [async-threads:1] [jit:ns] Interactive Elixir (1.17.3) - press Ctrl+C to exit (type h() ENTER for help) iex(1)> Supervisor.start_child(Testing.Supervisor, {Testing.Server, []}) {:ok, #PID<0.135.0>} iex(2)> Supervisor.start_child(Testing.Supervisor, {Testing.Server, [:x]}) {:error, {:already_started, #PID<0.135.0>}} But defining a child spec that sets the id: defmodule Testing.Server do use GenServer def start_link(_), do: GenServer.start_link(__MODULE__, []) def child_spec(arg) do id = Keyword.get(arg, :id) %{id: id, start: {__MODULE__, :start_link, [[]]}} end @impl GenServer def init(_), do: {:ok, nil} end solves the problem: Erlang/OTP 25 [erts-13.2.2.11] [source] [64-bit] [smp:14:14] [ds:14:14:10] [async-threads:1] [jit:ns] Interactive Elixir (1.17.3) - press Ctrl+C to exit (type h() ENTER for help) iex(1)> Supervisor.start_child(Testing.Supervisor, {Testing.Server, id: 1}) {:ok, #PID<0.135.0>} iex(2)> Supervisor.start_child(Testing.Supervisor, {Testing.Server, id: 1}) {:error, {:already_started, #PID<0.135.0>}} iex(3)> Supervisor.start_child(Testing.Supervisor, {Testing.Server, id: 2}) {:ok, #PID<0.136.0>}
- simoncion 2y ago> I'm talking about the behavior of the one_for_one supervisor: Oh, sure, you can vary the ID in non-'simple_one_for_one' supervisors there to make that work. Apologies for inducing you to write out all that transcript and code. But, OP's claim was: > - a lot of knowledge is implicit (try checking if you can dynamically add children to a Supervisor) which is just not fucking true no matter how you slice it. It's true that the relevant documentation doesn't literally say "Calling 'start_child/2' is valid for any kind of 'supervisor'. That's why it's here... to dynamically add children to a 'supervisor'.", but if one bothers to read the docs on supervisors and the function in question it's clear that that's the entire point of 'start_child/2'.