1

我有一个简单的应用程序target_interceptor,它在收到注册和注销消息后,启动或终止simple_one_for_one rpc_server_supervisor.

主管代码rpc_server_supervisor

init([]) ->
    MaxRestart = 5,
    MaxTime = 3600,
    {ok, {{simple_one_for_one, MaxRestart, MaxTime},
            [{rbmq_rpc_server, 
                {rbmq_rpc_server, start_link, []},
                temporary,
                10000,
                worker,
                [rbmq_rpc_server]}]}}.

注册消息target_interceptor

handle_cast({register, Args}, S = #state{channel = Channel, supervisor=Sup, refs=R, qs_link = QSLinks}) ->
    {Connection, QueueName, Node} = Args,   
    {Ok, Pid} = supervisor:start_child(Sup, [Connection, QueueName, Node]),
    Ref = erlang:monitor(process, Pid),
{noreply, S#state{refs=gb_sets:add(Ref,R), qs_link=orddict:append(binary_to_list(QueueName),Pid,QSLinks)}};

注销消息target_interceptor

handle_cast({unregister,{QueueName}}, S = #state{supervisor = Sup, qs_link = QSLinks}) ->
    Pid = orddict:fetch(QueueName,QSLinks) 
    case supervisor:terminate_child(Sup,Pid) of
         ok -> Success = true;
         Error -> io:format("Error ~p~n",[Error]),
                  Success = false
    end,
{noreply, S#state{qs_link=orddict:erase(QueueName,QSLinks)}}

我的 Erlang 版本是:R15B01

第一个问题是在处理注册操作时,元组 {OK, Pid} = {error, <0.57.0>}; 尽管它表明出现问题,但 Pid 57 上的 gen_server rbmq_rpc_server 工作正常并响应消息。为什么start_child函数的返回值错误?什么地方出了错?

第二个问题是在处理注销操作时,即使我引用 Pid 而不是 ChildID,supervisor:terminate_child(Sup,Pid) 也会返回 {error,simple_one_for_one)。为什么会这样?我如何动态地单独终止主管的孩子?

编辑:两者target_interceptor都由rpc_server_supervisor主管rbmq_sup_sup监督:

init({Nodeid, Node}) ->
    MaxRestart = 1,
    MaxTime = 3600,
    {ok, {{rest_for_one, MaxRestart, MaxTime},
            [{server,
                {target_interceptor, start_link, [target, self(), {Nodeid, Node}]},
                permanent,
                5000,
                worker,
                [target_interceptor]}]}}.

编辑:在 target_interceptor init() 函数中调用 rpc_server_supervisor(这里是 rbmq_sup_sup 主管):

handle_info({start_worker_supervisor, Sup}, S = #state{}) ->
    {ok, Pid} = supervisor:start_child(Sup, ?SPEC),
    link(Pid),
    {noreply, S#state{sup=Pid}};

-define(SPEC,
        {rpc_server_sup,
            {rpc_server_sup, start_link, []},
            temporary,
            10000,
            supervisor,
            [rpc_server_sup]}).
4

1 回答 1

1

我会在我有时间的时候补充。

第一点是{Ok,Pid}匹配任何元组,即使{error,Error}调用变量 Ok可能不是最佳选择。

一个快速的问题:在handle_cast({register,Args}, ...你做binary_to_list(QueueName)的关键,但handle_cast({unregister,{QueueName}}, ...你只是使用QueueName的关键。为什么?为什么要为每个 QueueName 保留一个 pid 列表,因为取消注册似乎将它们全部清除?这也意味着当你这样做时Pid = orddict:fetch(QueueName,QSLinks)Pid 将是一个 pids 列表而不是一个。

rbmq_sup_sup你才开始target_interceptor

rbmq_rpc_server进程是否已注册?

编辑:

我认为这样做时出错的原因unregister是您已经保存了orddict:append/3将值保存在list中的 pid ,即使是第一次,而orddict:fetch/2在这种情况下,您正在获取返回整个列表的值。列表也是如此Pid。然后,您尝试杀死作为Pidpid 列表的孩子,而不是supervisor:terminate_child/2正在抱怨的 pid。

如果您每个人只有一个 pid,QueueName那么您应该这样做orddict:store(binary_to_list(QueueName), Pid, QSLinks)。然后orddict:fetch/2将返回pid。

PS背后的想法orddict:append/3是您可以向同一个键添加更多值,并保留所有值的列表。

于 2014-10-14T13:17:02.617 回答