What handles the 'call' request in Elixir's supervisor after start_child

I’ve been reading through the code for Elixir supervisors for my own curiosity; when start_child is called in the code it then passes through to the function ‘call’ and that in turn does a GenServer.call with whatever arguments I have passed; my questions now being; the module passed as ‘supervisor’ doesn’t implement a handle call and the macro invoked when you ‘use Supervisor’ doesn’t inject anything for this request, so what handles this request for start_child or any of the calls in the module; the only occurrence of start_child are those three lines around the one I just linked to so I’m a little bit dumbfounded by this.

Recall that Elixir’s code builds on top of OTP’s supervisor. So I suspect that the handle_calls that you are looking for are here.

6 Likes

That clears everything up and things make sense; thank you.

As a small addendum, you could also use tracing to discover the module of which :handle_call is invoked. Here’s a small script which proves that :supervisor is indeed that module:

# start a supervisor
{:ok, supervisor} = Supervisor.start_link([], strategy: :one_for_one)

# trace function calls in supervisor
:erlang.trace(supervisor, true, [:call])
:erlang.trace_pattern({:_, :_, :_}, [])

# start a child
Supervisor.start_child(supervisor, %{
  id: :child,
  start: {Agent, :start_link, [fn -> nil end]}
})

# Pick up all traces, and print the first `:handle_call`
Stream.repeatedly(fn ->
  receive do
    x -> x
  end
end)
|> Stream.filter(&match?({:trace, _pid, :call, {_mod, :handle_call, _args}}, &1))
|> Enum.take(1)
|> hd()
|> IO.inspect()

# Output:
#
# {:trace, #PID<0.76.0>, :call,
#  {:supervisor, :handle_call,
#   [
#     {:start_child,
#      %{
#        id: :child,
#        start: {Agent, :start_link, [#Function<0.1373404 in file:test.exs>]}
#      }},
#     {#PID<0.73.0>, #Reference<0.4263660754.4251713537.141908>},
#     {:state, {#PID<0.76.0>, Supervisor.Default}, :one_for_one, [], :undefined,
#      3, 5, [], 0, Supervisor.Default,
#      {:ok, {%{intensity: 3, period: 5, strategy: :one_for_one}, []}}}
#   ]}}

6 Likes