Question

I'm trying to create a supervisor which handles adding dynamic gen_servers. for a reason something is failing and I'm not really sure what.

-module(supervisor_mod).
-behaviour(supervisor).

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

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

init(_Args) ->
    {ok, {{simple_one_for_one, 10, 60},
          [{example_proc, {example_proc, start_link, []},
            permanent, brutal_kill, worker, [example_proc]}]}}.

add_child(Name)->                                                                        
    supervisor:start_child(supervisor_mod,
                           {example_proc, {example_proc, start_link, []},
                            permanent, brutal_kill, worker, [example_proc]}).

and

-module(example_proc).
-behaviour(gen_server).

-export([start_link/0]).
-export([init/1, handle_call/3, handle_cast/2]).

start_link() ->
    gen_server:start_link(?MODULE, [], []).

init(Args) ->
    io:format("~p (~p) started...~n", [Args, self()]),
    {ok, []}.

handle_call(alloc, From, State) ->
    {reply, From, State}.

handle_cast({free, _Ch}, State) ->
    {noreply, State}.

in erl shell:

Eshell V5.8.2  (abort with ^G)
1> supervisor_mod:start_link().
{ok,{ok,<0.33.0>}}
2> supervisor_mod:add_child(aa).
{error,{'EXIT',{badarg,[{erlang,apply,
                                [example_proc,start_link,
                                 {example_proc,{example_proc,start_link,[]},
                                               permanent,brutal_kill,worker,
                                               [example_proc]}]},
                        {supervisor,do_start_child_i,3},
                        {supervisor,handle_call,3},
                        {gen_server,handle_msg,5},
                        {proc_lib,init_p_do_apply,3}]}}}

Any help/explanation/solution is appreciated, /s.

Was it helpful?

Solution

Read OTP Doc: in case of simple one for one strategy, in start_child function you can pass arguments as a list for the child start_link function of the child.

OTHER TIPS

When you use simple_one_for_one all the children will use the same ChildSpec, the one given in the init/1 callback and this initialisation can only return one ChildSpec. Also in this case the second argument to supervisor:start_child/2 must be a list and NOT a ChildSpec. This list is a list of extra arguments which is appended to the argument list given in the default ChildSpec and it is this combined argument list which is used when calling the child's start function. This is how the simple_one_for_one children all can use the same ChildSpec and still can get in specific arguments to them.

In your case as there was an empty list in the ChildSpec and you called start_child/2 with an empty list the total number of arguments to the start function was 0. Which matched how your start_link/0 function is defined.

An alternative is in your case to use one_for_one and start each child with its own ChildSpec. More complex but also more versatile.

Unfortunately this dual use of supervisor:start_child/2 has made it inconsistent in its arguments.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top