Erlang: supervisor(3), adding a child process

我与影子孤独终老i 提交于 2019-12-02 22:05:51

I did some research, and below is what I have.

First, this is a sample callback module of a supervisor:

-module(root_sup).
-behaviour(supervisor).
-export([start_link/0]).
-export([init/1]).

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

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

And this is a callback module of a child which will be added to the suprervision tree dynamically:

-module(ch1).

-behaviour(gen_server).

% Callback functions which should be exported
-export([init/1]).
-export([handle_cast/2]).

% user-defined interface functions
-export([start_link/0]).

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

init(_Args) ->
     io:format("ch1 has started (~w)~n", [self()]),
     % If the initialization is successful, the function
     % should return {ok,State}, {ok,State,Timeout} ..
     {ok, ch1State}.

handle_cast(calc, State) ->
     io:format("result 2+2=4~n"),
     {noreply, State};
handle_cast(calcbad, State) ->
     io:format("result 1/0~n"),
     1 / 0,
     {noreply, State}.

This is how we usually start the supervisor:

1> ch_sup:start_link().
{ok,<0.33.0>}

Now let's start our first child process:

2> {ok, Child1Pid} = supervisor:start_child(ch_sup, []).
ch1 has started (<0.35.0>)
{ok,<0.35.0>}

You can dynamically start child processes; let's start another child:

3> {ok, Child2Pid} = supervisor:start_child(ch_sup, []).
ch1 has started (<0.37.0>)
{ok,<0.37.0>}

You may see that our processes did start (note the last two):

4> erlang:processes().
[<0.0.0>,<0.2.0>,<0.4.0>,<0.5.0>,<0.7.0>,<0.8.0>,<0.9.0>,
 <0.10.0>,<0.11.0>,<0.12.0>,<0.13.0>,<0.14.0>,<0.15.0>,
 <0.16.0>,<0.17.0>,<0.18.0>,<0.19.0>,<0.20.0>,<0.21.0>,
 <0.22.0>,<0.23.0>,<0.24.0>,<0.25.0>,<0.26.0>,<0.27.0>,
 <0.31.0>,<0.33.0>,<0.35.0>,<0.37.0>]

Now let's make our first child process do something:

5> gen_server:cast(Child1Pid, calc).
result 2+2=4
ok

So far, so good. Now we'll make our first child to evaluate some bad code:

6> gen_server:cast(Child1Pid, calcbad).
result 1/0
ok    
7> 
=ERROR REPORT==== 10-Feb-2011::01:32:15 ===
** Generic server <0.35.0> terminating 
** Last message in was {'$gen_cast',calcbad}
** When Server state == ch1State
** Reason for termination == 
** {'function not exported',
       [{ch1,terminate,
            [{badarith,
                 [{ch1,handle_cast,2},
                  {gen_server,handle_msg,5},
                  {proc_lib,init_p_do_apply,3}]},
             ch1State]},
        {gen_server,terminate,6},
        {proc_lib,init_p_do_apply,3}]}
ch1 has started (<0.42.0>)
7>

In the report, you may see that the division by zero caused an exception and the process was terminated. But the supervisor takes care of it and immediately starts another child process (note the last line).

We can check to make sure that the other child process we started previously is still alive (note <0.37.0>):

7> erlang:processes().                 
[<0.0.0>,<0.2.0>,<0.4.0>,<0.5.0>,<0.7.0>,<0.8.0>,<0.9.0>,
 <0.10.0>,<0.11.0>,<0.12.0>,<0.13.0>,<0.14.0>,<0.15.0>,
 <0.16.0>,<0.17.0>,<0.18.0>,<0.19.0>,<0.20.0>,<0.21.0>,
 <0.22.0>,<0.23.0>,<0.24.0>,<0.25.0>,<0.26.0>,<0.27.0>,
 <0.31.0>,<0.33.0>,<0.37.0>,<0.42.0>]
8>

We can even make it do something for us:

8> gen_server:cast(Child2Pid, calc).   
result 2+2=4
9>

The following are the Erlang manual pages you'll want to read:

In Supervisor Behaviour section of the OTP Design Principles part of the Erlang docs there is an example of how to use simple_one_for_one and dynamic children. I recommend the whole Design Principles part as it provides much insight into how OTP works.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!