繁体   English   中英

Erlang Supervisor无法start_child,没有错误simple_one_for_one

[英]Erlang Supervisor fail to start_child with no errors simple_one_for_one

主管似乎无法默默地开始孩子......

这是主管

-behaviour(supervisor).
-export([start_socket/0, init/1, start_link/1]).

-define(SSL_OPTIONS, [{active, once},
                      {backlog, 128},
                      {reuseaddr, true},
                      {packet, 0},
                      {cacertfile, "./ssl_key/server/gd_bundle.crt"},
                      {certfile, "./ssl_key/server/cert.pem"},
                      {keyfile, "./ssl_key/server/cert.key"},
                      {password, "**********"}
                     ]).

start_link(Port) ->
    Role = list_to_atom(atom_to_list(?MODULE) ++ lists:flatten(io_lib:format("~B", [Port]))),
    supervisor:start_link({local, Role}, ?MODULE, [Port]).

init([Port]) ->
    R = ssl:listen(Port, ?SSL_OPTIONS),
    LSocket = case R of
                  {ok, LSock} ->
                      LSock;
                  Res ->
                      io:fwrite("gateway_sup Error: ~p~n", [Res])
              end,
    spawn_link(fun empty_listeners/0),
    ChildSpec = [{socket,
                  {gateway_serv, start_link, [LSocket]},
                  temporary, 1000, worker, [gateway_serv]}
                ],
    {ok, {{simple_one_for_one, 3600, 3600},
          ChildSpec
         }}.

empty_listeners() ->
    io:fwrite("---------------------- empty_listeners~n"),
    [start_socket() || _ <- lists:seq(1,128)],
    ok.

start_socket() ->
    io:fwrite("++++++++++++++++++++++ start_socket~n"),
    supervisor:start_child(?MODULE, []).

gen_server

-module(gateway_serv).

-behaviour(gen_server).
-export([start_link/1, init/1, handle_call/3, handle_cast/2, handle_info/2, code_change/3, terminate/2]).

start_link(LSocket) ->
io:fwrite("#################~n"),
    gen_server:start_link(?MODULE, [LSocket], []).

init([LSocket]) ->
io:fwrite("/////////////////~n"),
    gen_server:cast(self(), accept),
    {ok, #client{listenSocket=LSocket, pid=self()}}.

handle_cast(accept, G = #client{listenSocket=LSocket}) ->
    {ok, AcceptSocket} = ssl:transport_accept(LSocket),
    gateway_sup:start_socket(),
    case ssl:ssl_accept(AcceptSocket, 30000) of
    ok ->
        timer:send_after(10000, closingSocket),
        ssl:setopts(AcceptSocket, [{active, once}, {mode, list}, {packet, 0}]),
        {noreply, G#client{listenSocket=none, socket=AcceptSocket}};
    {error, _Reason} ->
        {stop, normal, G}
    end;
handle_cast(_, G) ->
    {noreply, G}.

显然从未调用gen_server的start_link / 1(使用io:fwrite检查)。

似乎无法找出原因......

当您注册主管时,您使用:

Role = list_to_atom(atom_to_list(?MODULE) ++ lists:flatten(io_lib:format("~B", [Port]))),

所以当你打电话时:

start_socket() ->
    io:fwrite("++++++++++++++++++++++ start_socket~n"),
    supervisor:start_child(?MODULE, []).

你正在打电话给一个不存在的主管。

你应该把它称为:

supervisor:start_child(Role, []).

您可以将Role作为参数传递给函数。

对我来说似乎很奇怪,你启动empty_listener调用start_socket()调用supervisor:在监督程序的init函数中的start_child,此时主管没有完成初始化阶段。 因此,要求主管启动子女的流程与主管本身之间存在竞争。

我认为这段代码应该在init函数之外:

  • 首先使用start_link(Port)启动主管,
  • 当它返回时调用函数start_socket()。

我做了一个使用这种模式的应用程序,我有两个级别的主管:

main supervisor (one_for_all strategy)
|                         |
|                         |
v                         v
application   ------->    supervisor (simple_one_for_one strategy)
server      start_child   worker factory
                          |
                          |
                          v*
                          many children

编辑:忘记这种竞争条件,

我做了一个测试,在init函数结束之前引入了一个延迟,我已经看到了start_child函数,等待init的结束,没有任何东西丢失。 OTP家伙比我想象的更加谨慎......

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM