Supervisor child_spec wraps list with list

Hello, I am trying to refresh my GenServer, Supervisor knowledge and I am trying to convert pooly from “The Little Elixir & OTP Guidebook” to newer Supervisor and child_spec forms.

So we have a main Supervisor module that on initialization it runs a GenServer

defmodule Pooly.Supervisor do
  use Supervisor

  require Cl

  def init(pool_config) do
    children =
        # Here I am trying to pass two arguments to Pooly.Server.start_link/2
        {Pooly.Server, [self(), pool_config]}
      |> Cl.inspect(label: "-cb The children")

    opts = [strategy: :one_for_all]

    Supervisor.init(children, opts)
    |> Cl.inspect(label: "-cb After init")
defmodule Pooly.Server do
  use GenServer

  def start_link(supervisor, pool_config) do
    GenServer.start_link(__MODULE__, [supervisor, pool_config], name: __MODULE__)

# ...

Unfortunately when I try to run this I get

$ iex -S mix
Erlang/OTP 22 [erts-10.7.2] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [hipe]

Compiling 1 file (.ex)
The children: [
   [#PID<0.198.0>, [mfa: {SampleWorker, :start_link, []}, size: 5]]}
After init: {:ok,
 {%{intensity: 3, period: 5, strategy: :one_for_all},
      id: Pooly.Server,
      start: {Pooly.Server, :start_link,
       [[#PID<0.198.0>, [mfa: {SampleWorker, :start_link, []}, size: 5]]]}
** (Mix) Could not start application pooly: Pooly.start(:normal, []) returned an error: shutdown: failed to start child: Pooly.Server
    ** (EXIT) an exception was raised:
        ** (UndefinedFunctionError) function Pooly.Server.start_link/1 is undefined or private
            (pooly 0.1.0) Pooly.Server.start_link([#PID<0.198.0>, [mfa: {SampleWorker, :start_link, []}, size: 5]])
            (stdlib 3.12.1) supervisor.erl:379: :supervisor.do_start_child_i/3
            (stdlib 3.12.1) supervisor.erl:365: :supervisor.do_start_child/2
            (stdlib 3.12.1) supervisor.erl:349: anonymous fn/3 in :supervisor.start_children/2
            (stdlib 3.12.1) supervisor.erl:1157: :supervisor.children_map/4
            (stdlib 3.12.1) supervisor.erl:315: :supervisor.init_children/2
            (stdlib 3.12.1) gen_server.erl:374: :gen_server.init_it/2
            (stdlib 3.12.1) gen_server.erl:342: :gen_server.init_it/6

So, when the children list is defined, the child spec has the arguments in a nice list.

 [#PID<0.198.0>, [mfa: {SampleWorker, :start_link, []}, size: 5]]}

But after Supervisor.init(children, opts) that list becomes item of a list

[[#PID<0.198.0>, [mfa: {SampleWorker, :start_link, []}, size: 5]]]}

and I believe init tries to call Pooly.Server.start_link/2 with that item as the only argument and offcourse it fails.

How can I fix that?

The new child_spec system normalized to only support ˋstart_link/1ˋ, unless you explicitly create a custom ˋchild_spec/1ˋ callback on the started module.

1 Like