Search code examples
erlangerlang-otpgen-servererlang-supervisor

Erlang: Supervisor start_child succeeds but no child is added


I'm working on building a supervisor in Erlang that looks like this:

-module(a_sup).
-behaviour(supervisor).

%% API
-export([start_link/0, init/1]).

start_link() ->
  {ok, supervisor:start_link({local,?MODULE}, ?MODULE, [])}.

init(_Args) ->
  RestartStrategy = {simple_one_for_one, 5, 3600},
  ChildSpec = {
    a_gen_server,
    {a_gen_server, start_link, []},
    permanent,
    brutal_kill,
    worker,
    [a_gen_server]
  },
  {ok, {RestartStrategy,[ChildSpec]}}.

And this is how my gen_server looks:

-module(a_gen_server).
-behavior(gen_server).

%% API
-export([start_link/2, init/1]).

start_link(Name, {X, Y}) ->
  gen_server:start_link({local, Name}, ?MODULE, [Name, {X,Y}], []),
  ok.

init([Name, {X,Y}]) ->
  process_flag(trap_exit, true),
  io:format("~p: position {~p,~p}~n",[Name, X, Y]),
  {ok, {X,Y}}.

My gen_server works completely fine. When I run the supervisor as:

1> c(a_sup).
{ok,a_sup}
2> Pid = a_sup:start_link().
{ok,{ok,<0.85.0>}}
3> supervisor:start_child(a_sup, [Hello, {4,3}]).
Hello: position {4,3}
{error,ok}

I couldn't understand where the {error, ok} is coming from, and if there is an error, then what is causing it. So this is what I get when I check the status of the children:

> supervisor:count_children(a_sup).
[{specs,1},{active,0},{supervisors,0},{workers,0}]

This means that there are no children registered with the supervisor yet despite it calling the init method of the gen_server and spawning a process? Clearly there is some error preventing the method to complete successfully but I can't seem to gather any hints to figure it out.


Solution

  • The problem is that a_gen_server:start_link (since that's the function used to in the child spec) is expected to return {ok, Pid}, not just ok.

    As the docs put it:

    The start function must create and link to the child process, and must return {ok,Child} or {ok,Child,Info}, where Child is the pid of the child process and Info any term that is ignored by the supervisor.

    The start function can also return ignore if the child process for some reason cannot be started, in which case the child specification is kept by the supervisor (unless it is a temporary child) but the non-existing child process is ignored.

    If something goes wrong, the function can also return an error tuple {error,Error}.