Erlang:supervisor(3),添加子进程

Posted

技术标签:

【中文标题】Erlang:supervisor(3),添加子进程【英文标题】:Erlang: supervisor(3), adding a child process 【发布时间】:2011-06-17 18:08:27 【问题描述】:

在哪里可以找到有关如何将动态子进程添加到现有主管的示例(simple_one_for_one 重启策略)?

【问题讨论】:

【参考方案1】:

在 Erlang 文档的 OTP Design Principles 部分的 Supervisor Behaviour 部分中,有一个如何使用 simple_one_for_one 和动态子代的示例。我推荐整个设计原则部分,因为它可以深入了解 OTP 的工作原理。

【讨论】:

【参考方案2】:

我做了一些研究,以下是我所拥有的。

首先,这是一个主管的回调模块示例:

-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.

这是一个孩子的回调模块,它将被动态添加到监督树中:

-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.

这就是我们通常启动supervisor的方式:

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

现在让我们开始我们的第一个子进程:

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

可以动态启动子进程;让我们开始另一个孩子:

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

您可能会看到我们的流程确实开始了(注意最后两个):

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>]

现在让我们的第一个子进程做一些事情:

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

到目前为止,一切都很好。现在我们将让我们的第一个孩子评估一些糟糕的代码:

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>

在报告中,您可能会看到除以零导致异常并终止进程。但是主管会处理它并立即启动另一个子进程(注意最后一行)。

我们可以检查以确保我们之前启动的另一个子进程仍然存在(注意&lt;0.37.0&gt;):

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>

我们甚至可以让它为我们做点什么:

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

以下是您想要阅读的 Erlang 手册页:

Supervisor Behaviour supervisor(3) gen_server(3)

【讨论】:

非常感谢。 my_start_child/0 在哪里? @shk: 哦,现在是凌晨 2 点 22 分,刚刚忘记重新导出此导出 :-) 此函数包含 supervisor:start_child(ch_sup, []). 我将编辑帖子。需要提到的一件重要的事情:您的孩子应该始终链接到主管,这就是为什么我在孩子启动功能中使用gen_server:start_link,而不仅仅是gen_server:start;否则主管将无法知道其子进程是否仍在运行或终止(正常或异常)。 “ch_sup”在哪里?我认为应该是“root_sup” 您从 erlang shell 启动了子进程。如何在主管启动后立即自动启动它?主管代码中是否有占位符,您可以添加主管:start_child(ch_sup, [])。 ? 这是不好的做法,您不应该取消链接

以上是关于Erlang:supervisor(3),添加子进程的主要内容,如果未能解决你的问题,请参考以下文章

使用supervisor进行进程管理

Supervisor进程管理

Erlang - 主管和 gen_fsm 上的异常退出

Erlang模块supervisor翻译

Erlang Supervisor 重启与宕机主机连接的策略

在初始化Erlang管理程序进程时添加gen_event处理程序