Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> 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...>. (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.)



I'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>}


> 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'.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: