万事皆有因
这件事情的开始是非常加单的,我想把几个模块独立化,变的可以重复使用。然后就创建了几个application,但是将几个模块整合到同一个项目的时候,犯了一个小小的错误,这个错误虽然不是很致命,但是是一个非常不好的。
产生原因
一开始,我有一个主干项目A,创建了SupervisorA。之后我创建了一个项目B,同时创建了一个SupervisorB。然后将两个项目整合的时候,我项目B中的模块X的start_link的代码如下面这样
-module(mod_x).
-export([start_link/1]).
start_link(opts)->
Child = {mod_y,{mod_y,start_link,[]},permanent,5000,worker,[mod_y],
supervisor:start_child(supervisor_b,Child).
然后我在主干项目中的SupervisorA的代码写成了这个样子
-module(supervisor_a).
-export([start_link/0]).
-export([init/1]).
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
init([])->
RestartStrategy = {one_for_one, 5, 10},
MFA = {mod_x,start_link,[]},
Child = {mod_x,MFA,permanent,5000,worker,[mod_x]},
{ok, { RestartStrategy,[Child]} }.
此时此刻我想大家已经看出问题了。
解释下
这样执行下来,当打开observer会观察到mod_y的进程是和SupervisorB关联,而不是和SupervisorA关联。我先说下为什么是和SupervisorB关联而不是和SupervisorA关联。然后再说下会有什么问题。
为什么和SupervisorB关联。
因为supervisor的start_child方法,是通过gen_server:call的方式,让指定的Supervisor通过start_link来创建child。而supervisor的start_link也是让指定的Supervisor通过mod:start_link来创建。换句话,就是supervisor并不是使用monitor机制,而是使用trap_exit机制来监控它所创建的进程。
那么会出现什么问题。
如果mod_y这个进程,不小心死掉了,那么当我们通过supervisor:which_children(SupervisorA)去寻找child的pid的时候,我们是无法拿到正确的Pid。原因就是上面那个,mod_y死掉后是SupervisorB负责重启的,而SupervisorA根本不知道这个变化。
来源:oschina
链接:https://my.oschina.net/u/236698/blog/664003