我有一个简单的应用程序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函数的返回值错误?出了什么问题?
第二个问题是当处理取消注册操作时,supervisor:terminate_child(Sup,Pid)返回{error,simple_one_for_one),即使我引用了Pid而不是ChildID。为什么它会像这样,我怎么能动态地和个别地终止我的主管的孩子?
编辑:
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(这里的Sup是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]}).
答案 0 :(得分:1)
我会加时间,因为我有时间。
第一点是{Ok,Pid}
匹配任何元组甚至{error,Error}
,因此调用变量 Ok
可能不是最佳选择。
一个简单的问题:在handle_cast({register,Args}, ...
中您为密钥执行了binary_to_list(QueueName)
,但在handle_cast({unregister,{QueueName}}, ...
中,您只需使用QueueName
作为密钥。为什么?为什么你为每个QueueName保留一个pid列表,因为unregister似乎清除了所有这些?这也意味着当你做Pid = orddict:fetch(QueueName,QSLinks)
时,Pid将是一个不是一个pid的列表。
在rbmq_sup_sup
中,您只能启动target_interceptor
。
rbmq_rpc_server
进程是否已注册?
修改强>
我认为执行unregister
时出错的原因是您已使用orddict:append/3
保存了pid,这样可以将值保存在列表中,即使是第一次,你得到orddict:fetch/2
的值,在这种情况下返回整个列表。所以Pid
是一个列表。然后尝试使用Pid
杀死孩子,这是pid的列表,而不是supervisor:terminate_child/2
抱怨的pid。
如果每QueueName
只有一个pid,那么您应该orddict:store(binary_to_list(QueueName), Pid, QSLinks)
。然后orddict:fetch/2
将返回pid。
P.S。 orddict:append/3
背后的想法是,您可以向同一个键添加更多值,并保留所有值的列表。