Erlang动态supervisor启动gen_server

发布于 2024-10-14 20:57:17 字数 514 浏览 7 评论 0原文

我有根主管创建其他主管:

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

init([]) ->
    RestartStrategy = {one_for_one, 5, 600},
    ListenerSup =
            {popd_listener_sup,
            {popd_listener_sup, start_link, []},
             permanent, 2000, supervisor, [popd_listener]},

    Children = [ListenerSup],

    {ok, {RestartStrategy, Children}}.

我有 gen_server - 监听器。创建主管后,如何使用 popd_listener_sup 主管运行此 gen_server ?

谢谢。

I have root supervisor that create other supervisor:

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

init([]) ->
    RestartStrategy = {one_for_one, 5, 600},
    ListenerSup =
            {popd_listener_sup,
            {popd_listener_sup, start_link, []},
             permanent, 2000, supervisor, [popd_listener]},

    Children = [ListenerSup],

    {ok, {RestartStrategy, Children}}.

And i have gen_server - listener. How can i run this gen_server with popd_listener_sup supervisor, when supervisor created?

Thank you.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

起风了 2024-10-21 20:57:18

根主管

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

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

init(_Args) ->
     RestartStrategy = {one_for_one, 10, 60},
     ListenerSup = {popd_listener_sup,
          {popd_listener_sup, start_link, []},
          permanent, infinity, supervisor, [popd_listener_sup]},
     Children = [ListenerSup],
     {ok, {RestartStrategy, Children}}.    

% supervisor can be shutdown by calling exit(SupPid,shutdown)
% or, if it's linked to its parent, by parent calling exit/1.
shutdown() ->
     exit(whereis(?MODULE), shutdown).
     % or
     % exit(normal).

如果子进程是另一个主管,则子规范中的 Shutdown 应设置为 infinity 以便为子树提供充足的关闭时间,并且 Type > 应该设置为 supervisor,这就是我们所做的。

子主管

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

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

init(_Args) ->
    RestartStrategy = {one_for_one, 10, 60},
    Listener = {ch1, {ch1, start_link, []},
            permanent, 2000, worker, [ch1]},
    Children = [Listener],
    {ok, {RestartStrategy, Children}}.

在这里,在子规范中,我们将 Shutdown 的值设置为 2000。整数超时值意味着主管将通过调用 exit(Child,shutdown) 告诉子进程终止,然后等待子进程返回带有原因关闭的退出信号。

来自 Erlang/OTP 文档的监听器

-module(ch1).
-behaviour(gen_server).

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

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

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

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

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

terminate(_Reason, _State) ->
     io:format("ch1: terminating.~n"),
     ok.

如果 gen_server 是
监督树并按其排序
主管终止该功能
模块:终止(原因,状态)
如果满足以下条件,则使用 Reason=shutdown 进行调用
满足以下条件:

  • gen_server 已设置为捕获退出信号,并且
  • 主管子规范中定义的关闭策略
    是一个整数超时值,不是
    残酷的杀戮。

这就是我们在 Module:init(Args) 中调用 erlang:process_flag(trap_exit, true) 的原因。

示例运行

启动根管理程序:

1> root_sup:start_link().
ch1 has started (<0.35.0>)
{ok,<0.33.0>}

根管理程序运行并自动启动其子进程,在我们的示例中为子管理程序。子supervisor依次启动其子进程;在我们的例子中,我们只有一个孩子,ch1

让我们让 ch1 评估正常代码:

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

现在一些错误的代码:

3> gen_server:cast(ch1, calcbad).
result 1/0
ok
ch1: terminating.

=ERROR REPORT==== 31-Jan-2011::01:38:44 ===
** Generic server ch1 terminating 
** Last message in was {'$gen_cast',calcbad}
** When Server state == []
** Reason for termination == 
** {badarith,[{ch1,handle_cast,2},
              {gen_server,handle_msg,5},
              {proc_lib,init_p_do_apply,3}]}
ch1 has started (<0.39.0>)
4> exit(normal).
ch1: terminating.
** exception exit: normal

正如您所看到的,子进程 ch1 被子主管 popd_listener_sup 重新启动(注意 < code>ch1 已启动 (<0.39.0>))。

由于我们的 shell 和根管理程序是双向链接的(在根管理程序函数 start_link/0 中调用 supervisor:start_link,而不是 supervisor:start), exit(normal) 导致根管理程序关闭,但其子进程有一些时间进行清理。

Root supervisor

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

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

init(_Args) ->
     RestartStrategy = {one_for_one, 10, 60},
     ListenerSup = {popd_listener_sup,
          {popd_listener_sup, start_link, []},
          permanent, infinity, supervisor, [popd_listener_sup]},
     Children = [ListenerSup],
     {ok, {RestartStrategy, Children}}.    

% supervisor can be shutdown by calling exit(SupPid,shutdown)
% or, if it's linked to its parent, by parent calling exit/1.
shutdown() ->
     exit(whereis(?MODULE), shutdown).
     % or
     % exit(normal).

If the child process is another supervisor, Shutdown in child specification should be set to infinity to give the subtree ample time to shutdown, and Type should be set to supervisor, and that's what we did.

Child supervisor

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

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

init(_Args) ->
    RestartStrategy = {one_for_one, 10, 60},
    Listener = {ch1, {ch1, start_link, []},
            permanent, 2000, worker, [ch1]},
    Children = [Listener],
    {ok, {RestartStrategy, Children}}.

Here, in a child specification, we set value of Shutdown to 2000. An integer timeout value means that the supervisor will tell the child process to terminate by calling exit(Child,shutdown) and then wait for an exit signal with reason shutdown back from the child process.

Listener

-module(ch1).
-behaviour(gen_server).

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

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

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

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

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

terminate(_Reason, _State) ->
     io:format("ch1: terminating.~n"),
     ok.

From Erlang/OTP documentation:

If the gen_server is part of a
supervision tree and is ordered by its
supervisor to terminate, the function
Module:terminate(Reason, State) will
be called with Reason=shutdown if
the following conditions apply:

  • the gen_server has been set to trap exit signals, and
  • the shutdown strategy as defined in the supervisor's child specification
    is an integer timeout value, not
    brutal_kill.

That's why we called erlang:process_flag(trap_exit, true) in Module:init(Args).

Sample run

Starting the root supervisor:

1> root_sup:start_link().
ch1 has started (<0.35.0>)
{ok,<0.33.0>}

Root supervisor is run and automatically starts its child processes, child supervisor in our case. Child supervisor in turn starts its child processes; we have only one child in our case, ch1.

Let's make ch1 evaluate normal code:

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

Now some bad code:

3> gen_server:cast(ch1, calcbad).
result 1/0
ok
ch1: terminating.

=ERROR REPORT==== 31-Jan-2011::01:38:44 ===
** Generic server ch1 terminating 
** Last message in was {'$gen_cast',calcbad}
** When Server state == []
** Reason for termination == 
** {badarith,[{ch1,handle_cast,2},
              {gen_server,handle_msg,5},
              {proc_lib,init_p_do_apply,3}]}
ch1 has started (<0.39.0>)
4> exit(normal).
ch1: terminating.
** exception exit: normal

As you may see child process ch1 was restarted by the child supervisor popd_listener_sup (notice ch1 has started (<0.39.0>)).

Since our shell and root supervisor are bidirectionally linked (call supervisor:start_link, not supervisor:start in the root supervisor function start_link/0), exit(normal) resulted in the root supervisor shutdown, but its child processes had some time to clean up.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文