2

Hello i am trying to run a supervisor whose workers are not gen_server(s). My supervisor is defined in the same module as the worker for brevity:

I keep getting this error and i have tried putting the MFA attribute in [ ] to no avail.I have also put the ChildSpec in [ ]. What am i missing ?

I do not want my supervisor to have any workers when starting it.

Error

>  X=sup:start_link().
> ** exception error: no match of right hand side value {error,
>                                                        {bad_start_spec,[]}}
>      in function  sup:start_link/0 (c:/Erlang/ProcessPool/sup.erl, line 6)
> =CRASH REPORT==== 5-Apr-2020::22:20:32.918000 ===   crasher:
>     initial call: supervisor:sup/1
>     pid: <0.280.0>
>     registered_name: []
>     exception exit: {bad_start_spec,[]}
>       in function  gen_server:init_it/6 (gen_server.erl, line 358)
>     ancestors: [<0.273.0>]
>     message_queue_len: 0
>     messages: []
>     links: [<0.273.0>]
>     dictionary: []
>     trap_exit: true
>     status: running
>     heap_size: 376
>     stack_size: 27
>     reductions: 205   neighbours:

Module

-module(sup).
-behaviour(supervisor).
-compile([export_all]).

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

init(_Args) ->
     RestartStrategy = {simple_one_for_one, 10, 60},
    {ok, {RestartStrategy,[]}}.

add(Sup,Value)->                #adding child
    ChildSpec = {
                  ch1, 
                  {sup, start, [Value]},
                  permanent,
                  brutal_kill, 
                  worker, 
                  [ch1]
                },
    supervisor:start_child(Sup,ChildSpec).


start([Value])->                                    #child's start_link equivalent (non-genserver)
    spawn_link(?MODULE,initworker,[self(),Value]).

initworker(From,Value)->                            #child's init
    receive 
       MSG->From ! {got_msg,Value,MSG}
    end.
2240
  • 1,547
  • 2
  • 12
  • 30
Bercovici Adrian
  • 8,794
  • 17
  • 73
  • 152

1 Answers1

3

As you using simple_one_for_one, You should define ChildSpec in init and all children use the same ChildSpec .

If you need different, then use 'one_for_one' strategy instead.

For simple_one_for_one:

The second argument of supervisor:start_child/2 must be a list which will be combined with default arguments to child start function arguments defined in ChildSpec.

Here I quickly modified the code to make it work for you.

-module(sup).
-behaviour(supervisor).
-compile([export_all]).

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

init(_Args) ->
     RestartStrategy = {simple_one_for_one, 10, 60},
     ChildSpec = {
                  ch1, 
                  {sup, start, []},
                  permanent,
                  brutal_kill, 
                  worker,
                  [sup]
                },
    {ok, {RestartStrategy,[ChildSpec]}}.

add(Sup,Value)->                
    supervisor:start_child(Sup,[Value]).


start(Value)->                                    
    P = spawn(?MODULE, initworker,[]),
    P!{self(),Value},
    {ok,P}.

initworker()->                            
    receive 
       {From, MSG} -> io:format(" Value is ~p~n", [MSG])
    end.
  • I do not understand.Can't the `ChildSpec` be added after the `init` ? I mean when i use `supervisor:start_child` can't i set its child spec?Does the supervisor need to know the spec before any child is added? – Bercovici Adrian Apr 07 '20 at 15:41
  • Starting a child with different code is against how 'simple_one_for_one' supervisors works. Please check the doc here http://erlang.org/doc/man/supervisor.html#check_childspecs-1 . As stated in my answer you can try 'one-for-one' supervisor to have ChildSpec after 'init'. more info: https://stackoverflow.com/questions/11120207/erlang-starting-a-child-from-the-supervisor-module https://stackoverflow.com/questions/41190705/eralng-simple-one-for-one-supervisor-does-not-restart-child – Adinarayana Immidisetti Apr 07 '20 at 17:28
  • Ok but is there a way to inject data from my `ChildSpec` inside each child that gets spawned afterwards? In my example id like to add some arguments in the `MFA` of `init()` that would get passed to all children that are added. – Bercovici Adrian Apr 07 '20 at 17:39
  • If you need ChildSpec after init. Modify code to use one_for_one like this. https://www.codepile.net/pile/0zeJrpow or above code in the answer also can add argument dynamically if you call sup:add(sup:start_link(),"newargument"). – Adinarayana Immidisetti Apr 07 '20 at 18:59