我想在我正在构建的分布式应用程序中使用erlang的OTP管理程序.但我无法弄清楚这种主管如何监控在远程节点上运行的进程.与erlang的start_link函数不同,start_child没有用于指定将在其上生成子节点的Node的参数.
OTP主管是否可以监控远程孩子,如果没有,我如何在erlang中实现这一点?
最佳答案 supervisor:start_child / 2可以跨节点使用.
你混淆的原因只是关于执行环境的混淆(有时候有点难以保持直线).任何OTP生成都涉及三个过程:
>请求者
>主管
>催生过程
请求者的上下文是主管:start_child / 2被调用的上下文 – 而不是主管本身的上下文.您通常会通过导出一个将调用包装到supervisor的函数来提供一个supervisor接口:spawn_child / 2:
do_some_crashable_work(Data) ->
supervisor:start_child(sooper_dooper_sup, [Data]).
这可以从管理程序模块定义和导出,根据“service manager/supervisor/workers” idiom或其他任何内容在“管理器”类型的进程内部定义.但是,在所有情况下,除主管之外的某些进程正在进行此调用.
现在仔细查看主管的Erlang文档:start_child / 2(here和an R19.1 doc mirror,因为有时因为某些原因,erlang.org很难).请注意,类型sup_ref()
可以是注册名称,pid(),{global,Name}或{Name,Node}.当使用pid(),{global,Name}或{Name,Node}元组进行调用时,请求者可能在任何其他节点上调用超级用户的节点上.
不过,主管并不只是随意开球.它有一个child_spec()
它正在关闭,并且规范告诉主管如何调用以启动该新进程.第一次调用子模块是在主管的上下文中进行的,并且是一个自定义函数.虽然我们通常将其命名为start_link / N,但它可以作为启动的一部分执行任何我们想要的操作,包括声明要生成的特定节点.所以现在我们结束这样的事情:
%% Usually defined in the requestor or supervisor module
do_some_crashable_work(SupNode, WorkerNode, Data) ->
supervisor:start_child({sooper_dooper_sup, SupNode}, [WorkerNode, Data]).
有一个孩子的规格,如:
%% Usually in the supervisor code
SooperWorker = {sooper_worker,
{sooper_worker, start_link, []},
temporary,
brutal_kill,
worker,
[sooper_worker]},
这表明第一次调用是sooper_worker:start_link / 2:
%% The exported start_link function in the worker module
%% Called in the context of the supervisor
start_link(Node, Data) ->
Pid = proc_lib:spawn_link(Node, ?MODULE, init, [self(), Data]).
%% The first thing the newly spawned process will execute
%% in its own context, assuming here it is going to be a gen_server.
init(Parent, Data) ->
Debug = sys:debug_options([]),
{ok, State} = initialize_some_state(Data)
gen_server:enter_loop(Parent, Debug, State).
你可能想知道proc_lib
的所有问题是什么.事实证明,虽然从多节点系统中的任何地方调用spawn来启动多节点系统中其他任何地方的spawn是可能的,但它只是一种非常有用的业务方式,因此gen_ *行为甚至proc_lib:start_link/N
都没有一种方法来声明生成新进程的节点.
理想情况下,节点知道如何初始化自己并在集群运行后加入集群.您的系统提供的任何服务通常最好在群集中的其他节点上进行复制,然后您只需编写一种选择节点的方法,这样您就可以完全理解启动业务,因为它现在是节点本地的每个案例.在这种情况下,无论你的普通经理/主管/工人代码做什么都不需要改变 – 事情刚刚发生,并且请求者的PID恰好在另一个节点上并不重要,即使该PID是地址到必须返回哪些结果.
换句话说,我们并不真的想在任意节点上产生工作者,我们真正想做的是升级到更高级别并请求某些工作由另一个节点完成而不是真正关心它是如何发生的.请记住,要生成基于{M,F,A}调用的特定函数,您调用的节点必须能够访问目标模块和函数 – 如果它已经拥有代码的副本,为什么不是调用节点的副本?
希望这个答案解释的不仅仅是困惑.