ca88亚洲城网站创办一个erlang节点后,一个监察被称为子进程的任何进度的进程

gen_server

概要

erlang应用脚本stop分析

实际上那篇小说的名字应该是怎么样安全关闭erlang应用越发科学。

概要
  通用服务器行为
描述

  通用监督者行为

erlang应用脚本生成

行使rebar工具,成立一个erlang节点后,
<pre>
./rebar create-node nodeid=hook_heroes
</pre>
下一场在rel目录里面,执行打包命令
<pre>
./rebar generate
</pre>
会转变完整的利用包,目录如下:
<pre>
bin erts-6.0 lib log releases
</pre>
bin里面,有一个起动脚本名字和节点名字一样的,那里是hook_heroes

终止服务的时候,近年来使用
<pre>
./hook_heroes stop
</pre>

  行为模块达成服务器的客户端-服务器涉及。一个通用的服务器进度使用那一个模块将促成一组正式的接口成效,包蕴跟踪和错误报告成效。它也契合OTP进度监控树。精通愈来愈多新闻参考OTP设计原则。

 

对于hook_heroes stop分析

hook_heroes stop调用如下
<pre>
%%Tell nodetool to initiate a stop
$NODETOOL stop
ES=$?
if [ “$ES” -ne 0 ]; then
exit $ES
fi
</pre>
这里的nodetool来自
<pre>
NODETOOL=”$ERTS_PATH/escript $ERTS_PATH/nodetool
</pre>
即erts包下边的nodetool脚本,传入的参数stop
nodetool是一个escript脚本,成效就是“Helper Script for interacting with
live nodes”

<pre>
case RestArgs of
[“getpid”] ->
io:format(“~p\n”,
[list_to_integer(rpc:call(TargetNode, os, getpid, []))]);
[“ping”] ->
io:format(“pong\n”);
[“stop”] ->
io:format(“~p\n”, [rpc:call(TargetNode, init, stop, [], 60000)]);
…….
</pre>

可以观望,间接接纳的是rpc:call()方法:调用TargetNode的init模块的stop方法,传入的参数为[],上面来看望init模块的stop方法。

  gen_server假定所有特定部分位于一个回调模块,它导出的一组预订义的意义。行为函数和回调函数的关系可以作证如下:

描述

init模块的stop()方法调用

init 模块的文档给的诠释是:“Coordination of System Startup”,
stop方法的注明是:
<pre>
All applications are taken down smoothly, all code is unloaded, and all
ports are closed before the system terminates
</pre>
众所周知就是用来系统关闭的,关键是需求探视他是怎么关闭系统的。

  gen_server module Callback module
  —————– —————
  gen_server:start_link —–> Module:init/1

  一个兑现监督者的表现模块,一个监控被称为子进度的别的进度的进程。一个子历程可以是另一个监督者或工小编经过。工小编经过日常的完毕利用gen_event,gen_fsm和gen_server中的行为。监督者使用那么些模块完成一组正式的接口函数和概括跟踪和错误报告的功力。监督者被用来构建称为监控树的分支进程协会,一个构建容错应用的很好的方法。参考OTP设计原理得到更加多音讯。

函数入口:

<pre>
stop() -> init ! {stop,stop}, ok.
</pre>
给init模块发送温馨发送一个{stop,stop}新闻,

init自己循环接收音讯
<pre>
loop(State) ->
receive
{‘EXIT’,Pid,Reason} ->
Kernel = State#state.kernel,
terminate(Pid,Kernel,Reason), %% If Pid is a Kernel pid, halt()!
loop(State);
{stop,Reason} ->
stop(Reason,State);
{From,fetch_loaded} -> %% The Loaded info is cleared in
Loaded = State#state.loaded, %% boot_loop but is handled here
From ! {init,Loaded}, %% anyway.
loop(State);
{From, {ensure_loaded, _}} ->
From ! {init, not_allowed},
loop(State);
Msg ->
loop(handle_msg(Msg,State))
end.
</pre>

协作到{stop,Reason},进入stop(Reason,State)那里调用,Reason为stop,
来打那里
<pre>
stop(Reason,State) ->
BootPid = State#state.bootpid,
{_,Progress} = State#state.status,
State1 = State#state{status = {stopping, Progress}},
clear_system(BootPid,State1),
do_stop(Reason,State1).
</pre>
一言九鼎看下clear_system函数和do_stop函数

  gen_server:call
  gen_server:multi_call —–> Module:handle_call/3

 

clear_system()函数

clear_system()那里的成效就是关门虚拟机中的进度,只用多少个函数调用
<pre>
clear_system(BootPid,State) ->
Heart = get_heart(State#state.kernel), %A
shutdown_pids(Heart,BootPid,State), %B
unload(Heart). %C
</pre>

A和C都是在处理erlang启动参数heart,其意义在vm.args有证实
<pre>
Heartbeat management; auto-restarts VM if it dies or becomes
unresponsive
(Disabled by default..use with caution!)
-heart
</pre>
相似景观下,不利用-heart
俺们这里只看shutdown_pids()咋做的。

  gen_server:cast
  gen_server:abcast     —–> Module:handle_cast/2

  监督者设定哪些子进度被监控的概念,位于导出一组预订义函数的回调模块。

shutdown_pids()函数

<pre>
shutdown_pids(Heart,BootPid,State) ->
Timer = shutdown_timer(State#state.flags),
catch shutdown(State#state.kernel,BootPid,Timer,State),
kill_all_pids(Heart), % Even the shutdown timer.
kill_all_ports(Heart),
flush_timout(Timer).
</pre>

此处首先关闭定时器,然后倒闭kernel进度,然后再kill其他的进程。

关闭kernel进程
<pre>
%%
%% A kernel pid must handle the special case message
%% {‘EXIT’,Parent,Reason} and terminate upon it!
%%
shutdown_kernel_pid(Pid, BootPid, Timer, State) ->
Pid ! {‘EXIT’,BootPid,shutdown},
shutdown_loop(Pid, Timer, State, []).
</pre>

  -               —–> Module:handle_info/2

 

什么是erlang的kernel进程?

那句话是必不可缺: A kernel pid must handle the special case message and
terminate upon it!
那就是说什么样是kernel进度呢?
看下bin/start.script
<pre>

{kernelProcess,heart,{heart,start,[]}},
{kernelProcess,error_logger,{error_logger,start_link,[]}},
{kernelProcess,application_controller,
{application_controller,start,
[{application,kernel,

</pre>

那些带kernelProcess标签的经过都是, 更加是application!

来自http://blog.yufeng.info/archives/1411

故supervisor_tree收到的是{‘EXIT’,BootPid,shutdown}

kill其他的进度:
<pre>
kill_all_pids(Heart) ->
case get_pids(Heart) of
[] ->
ok;
Pids ->
kill_em(Pids),
kill_all_pids(Heart) % Continue until all are really killed.
end.
</pre>
末段跟下去,使用的是
<pre>
exit(Pid,kill)
</pre>
向各样进度发送kill新闻。

  -               —–> Module:terminate/2

  除非另作表明,即使指定的supervisor不设有或提交错误参数,该模块所有函数会败北。

supervisor terminate方法

supervisor中的terminate()方法如下:
<pre>
-spec terminate(term(), state()) -> ‘ok’.

terminate(_Reason, #state{children=[Child]} = State) when
?is_simple(State) ->
terminate_dynamic_children(Child,
dynamics_db(Child#child.restart_type,
State#state.dynamics),
State#state.name);
terminate(_Reason, State) ->
terminate_children(State#state.children, State#state.name).
</pre>

分为simple_one_for_one和非simple_one_for_one二种状态。
terminate_dynamic_children()方法:
<pre>

EStack = case Child#child.shutdown of
brutal_kill ->
?SETS:fold(fun(P, _) -> exit(P, kill) end, ok, Pids),
wait_dynamic_children(Child, Pids, Sz, undefined, EStack0);
infinity ->
?SETS:fold(fun(P, _) -> exit(P, shutdown) end, ok, Pids),
wait_dynamic_children(Child, Pids, Sz, undefined, EStack0);
Time ->
?SETS:fold(fun(P, _) -> exit(P, shutdown) end, ok, Pids),
TRef = erlang:start_timer(Time, self(), kill),
wait_dynamic_children(Child, Pids, Sz, TRef, EStack0)
end,

</pre>

可以看看ChildSpec中的ShowDown字段的安装对于关闭子进程的影响:
brutal_kill:发送kill信息,这几个音信是无法捕捉的。即使要是worker设置了process_flag(trap_exit,
true),依旧不会吸纳{‘EXIT’,_FROM,REASON}那个新闻;
infinity和提姆e都会向监督的worker进度发送shutdown信号,那里worker做了
process_flag(trap_exit,
true),自然会吸纳{‘EXIT’,_FROM,REASON}。唯一的分别是infinity会一直等候,提姆e会设置一个过期:若是超时过了,那么supervisor会发送kill信号,直接杀死。
基于上边的解析,简单和erlang文档中对此gen_server terminate()方法
<pre>
If the gen_server is part of a supervision tree and is ordered by its
supervisor to terminate, this function will be called with
Reason=shutdown if the following conditions apply:

the gen_server has been set to trap exit signals, and
the shutdown strategy as defined in the supervisor’s child specification
is an integer timeout value, not brutal_kill.
</pre>

  -               —–> Module:code_change/3

 

supervisor曾几何时调用terminate()方法

说到底一个题目来了,supervisor几时调用terminate()方法?之前分析到,关闭kernel进度的时候,supervisor监控树进度会吸纳来自BootPid的{‘EXIT’,BootPid,shutdown}音信。我们领悟supervisor实际上一个gen_server,那么去探望他的handle_info()方法好了。

<pre>
-spec handle_info(term(), state()) ->
{‘noreply’, state()} | {‘stop’, ‘shutdown’, state()}.

handle_info({‘EXIT’, Pid, Reason}, State) ->
case restart_child(Pid, Reason, State) of %重启child
{ok, State1} -> %A
{noreply, State1};
{shutdown, State1} -> %B
{stop, shutdown, State1}
end;

handle_info(Msg, State) ->
error_logger:error_msg(“Supervisor received unexpected message:
pn”,
[Msg]),
{noreply, State}.
</pre>

此间代码显著都是handle_info
child发送过来的信号,调用restart_child()。在跟踪restart_child()进去,也从不看到原因:因为传播Pid并不是Child,而是BootPid,总是会走到A分支,也就是说不会调用terminate方法。那里陷入困境。
新生读书了supervisor文档,发现照旧没有terminate()方法的求证,再度陷入困境。
最终,想起supervisor实际上一个gen_server,应该去探望gen_server()文档对于terminate()方法地证实。
<pre>

Even if the gen_server is not part of a supervision tree, this function
will be called if it receives an ‘EXIT’ message from its parent. Reason
will be the same as in the ‘EXIT’ message.

</pre>
此处表达,只要gen_server收到了来自parent的’EXIT’
message,terminate()方法就会调用。符合从前分析地:
<pre>
{‘EXIT’,BootPid,shutdown}
</pre>
关于BootPid和SuperVisor是不是是parent关系,那里暂时没时间研商:然而一定会是,否则,顶层的sup一定要有人布告关闭啊,而且BootPid从命名来看,至极有可能。那里留一个坑前面填上,重假使init:start()的开行。

  若是一个回调函数败北或回到一个错误的值,gen_server将会停下。

  监督规则:

其它
  • 事先代码中的player进度的child_spec的show_down写的是brutal_kill,那里肯定写错了;那么应用关闭的时候,自然不会调用terminate方法
  • Erlang OTP之terminate
    深切解析
    那篇作品是基于erlang
    14A本子的,他提出利用one_for_one。原因很简短,erlang
    14A中,supervisor的terminate()函数如下
    <pre>
    terminate(_Reason, State) ->
    terminate_children(State#state.children, State#state.name),
    ok.
    </pre>
    对于17本子,可以看出,那里没有拍卖单独simple_one_for_one的情况。因为simple_one_for_one和one_for_one的child音信在supervisor里面储存的是不均等的:前者child存储在dynamics属性,
    后来人存储在children属性。erlang
    14A的版本只处理了children里面的child,对于simple_one_for_one的child直接没有处理。
    对此那篇文章的试验,我在温馨电脑上也做了试验,确实和他的结果分裂。

  gen_server处理系统音信,它们记录在sys。sys模块可以用来调节gen_server。

  监督者负责启动、截止和督查它的子进度。监督者的焦点情维是,它应该保险它的子进程活着,须求时重启它们。

参考资料

  请注意,gen_server并不活动地破获退出信号,这么些必须旗帜明显地在回调模块启动。

 

  除非另作阐明,若是指定的gen_server不设有或提交错误参数,该模块所有函数会失利。

  监督者的子进度被定义为子规范列表。当监督者被启动时,子进度依照这么些列表从左到右按梯次被启动。当监督者终止时,它首先按相反的启动顺序,从右到左终止它的子进度。

  假诺一个回调函数指定”hibernate”而不是超时值,该gen_server进度会进去休眠。那可能是立竿见影的,借使服务器猜度闲置很长一段时间。然则那一个功能应该小心使用,使用休眠意味着至少有五个废物收集(休眠又很快唤起),不是您想做的政工里面,每回调用一个坚苦的服务器。

 

导出

  监督者可以有以下重启策略之一:

start_link(Module, Args, Options) -> Result
start_link(ServerName, Module, Args, Options) -> Result
  Types:
    ServerName = {local,Name} | {global,GlobalName} | {via,Module,ViaName}
      Name = atom()
      GlobalName = ViaName = term()
    Module = atom()
    Args = term()
    Options = [Option]
      Option = {debug,Dbgs} | {timeout,Time} | {spawn_opt,SOpts}
      Dbgs = [Dbg]
        Dbg = trace | log | statistics | {log_to_file,FileName} | {install,{Func,FuncState}}
      SOpts = [term()]
    Result = {ok,Pid} | ignore | {error,Error}
      Pid = pid()
      Error = {already_started,Pid} | term()

  one_for_one –
借使实进度终止,应重新启航,唯有子进度遭到震慑。

  创立一个gen_server进度作为监控树的一有的。函数应该直接或直接地被supervisor调用。它将有限援助gen_server在其他地方被链接到supervisor。

  one_for_all –
若是实进度终止,应重新开动,所有其余子进度终止,那么所有的子进程被启动。

  gen_server进程调用Module:init/1举办开头化。为力保同步启动进度,start_link/3,4直至Module:init/1执行到位才能回去。

  rest_for_one –
即使实进程终止,应重新启航,前边的子进度,也就是说,按启动顺序,被终止进度的末端的子进程被为止。那么,终止进度和它背后所有的子进程被重启。

  如果ServerName={local,Name},gen_server使用register/2被登记为当地的Name。要是ServerName={global,GlobalName},gen_server使用global:register_name/2被注册为大局的GlobalName。假使没有提供Name,gen_server不会被登记。假设ServerName={via,Module,ViaName},gen_server将会用Module代表的注册表注册。Module回调应该导出函数register_name/2,
unregister_name/1, whereis_name/1 和
send/2,它们表现得像global模块对应的函数。由此,{via,global,GlobalName}是一个使得地引用。

  simple_one_for_one –
简化的one_for_one监督者,其中,所有的子进度被动态增加相同进度类型的实例,也就是,运行相同的代码。

  Module是回调模块的名称。

 

  Args是任意term,作为参数传递给Module:init/1。

  对于simple_one_for_one监督者,函数delete_child/2 和
restart_child/2是行得通的。即使指定的监督者使用该重启策略,会再次来到{error,simple_one_for_one}。

  若是采取是{timeout,提姆e},gen_server被允许开销提姆(Tim)e毫秒开端化,或者它将被停止,并且启动函数再次回到{error,timeout}。
  若是选用是{debug,Dbgs},对于Dbgs里的各样条目,对应的sys函数将会被调用。参见sys。
  假诺拔取是{spawn_opt,SOpts},SOpts将被视作挑选列表传递给spawn_opt内建函数,它被用来暴发gen_server。

 

  如果gen_server被成功开创和初叶化,函数重回{ok,Pid},其中Pid是gen_server的进度号。假设已经存在使用指定ServerName的长河,函数重返{error,{already_started,Pid}},其中,Pid是不行进度的进度号。

  在simple_one_for_one监督者下,通过给定子进度的进度号作为第一个参数,函数terminate_child/2可被用于子进度。假如实规范标识符被采纳,terminate_child/2将返回{error,simple_one_for_one}。

  如若Module:init因为Reason失败,函数重返{error,Reason}。如若Module:init/1重返{stop,Reason}
或 ignore,进度被停止并且函数会独家重临{error,Reason} 或 ignore。

 

start(Module, Args, Options) -> Result
start(ServerName, Module, Args, Options) -> Result
  Types:
    同 start_link/3,4。

  因为一个simple_one_for_one监督者可以有恒河沙数的子进度,它在同一时间将它们关闭。所以,它们被甘休的次第没有被定义。出于同样的案由,它恐怕有一个付出对于关闭策略。

  创设一个单身的gen_server进程,也就是,gen_server不是监控树的一部分还要没有监督进程。

 

  参看start_link/3,4摸底参数和重临值的描述。

  为严防监督者进入子进度终止和重启的然而循环,使用八个整数马克斯R 和
马克斯(Max)T定义最大重启频率。假设在马克斯T秒重启超越马克斯(Max)R暴发,监督者终止所有子进度,随后停下它自己。

call(ServerRef, Request) -> Reply
call(ServerRef, Request, Timeout) -> Reply
  Types:
    ServerRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()
      Node = atom()
      GlobalName = ViaName = term()
    Request = term()
    Timeout = int()>0 | infinity
    Reply = term()

 

  通过发送请求向引用名为ServerRef的gen_server进行协同调用,直到回复到达或产生超时。gen_server将调用Module:handle_call/3处理请求。

  那是子规范的类型定义:

  ServerRef可以是:

child_spec() = {Id,StartFunc,Restart,Shutdown,Type,Modules}
  Id = term()
  StartFunc = {M,F,A}
    M = F = atom()
     A = [term()]
   Restart = permanent | transient | temporary
   Shutdown = brutal_kill | int()>0 | infinity
   Type = worker | supervisor
   Modules = [Module] | dynamic
    Module = atom()
  • 进程号;
  • Name,gen_server被本地注册的名号;
  • {Name,Node},gen_server在其他节点被地点注册;
  • {global,GlobalName},gen_server被全局注册;
  • {via,Module,ViaName},gen_server通过代表的进度注册表注册;

  
Id是一个称呼,在里面被监督者用于标识子规范。

  Request是一个任意term,它当作内部的参数传递给Module:handle_call/3。

  

  提姆eout是一个过量零的整数,它指定多少飞秒等待每个回复,原子infinity会无限期的等待。默许值是5000。如若在指定时间内并未收到回复,函数会调用战败。如果调用者捕获退步并且继续运行,服务器仅仅晚些回复,它将在任哪天候到达随后进入调用者的音讯队列。对此,调用者必须准备那种境况,并且不保留任何杂质音信,它们是多少个元素元组作为第四个因素。

  
StartFunc定义函数调用用于启动子进程。它应有是一个模块-函数-参数元组{M,F,A}用作apply(M,F,A)。

  再次来到值Reply被定义在Module:handle_call/3的回来值里。

  
启动函数必须创设和链接到子进度,应该回到{ok,Child}或{ok,Child,Info},其中Child是子进程的长河号,Info是任意term被监督者忽略。

  调用可能会因为两种原因战败,包罗超时和在调用前和调用进程中gen_server死掉。

 

  在调用时期当连接到客户端,若是服务器死掉,有时会损耗退出信息,那些过时的行事早就在OTP
R12B/Erlang 5.6中移除。

  
若是实进度因为部分缘由不可以开行,启动函数也可以回来ignore,那种气象,子规范将会被监督者保存(除非它是temporary进度),但不设有的子进度将被忽视。

multi_call(Name, Request) -> Result
multi_call(Nodes, Name, Request) -> Result
multi_call(Nodes, Name, Request, Timeout) -> Result
  Types:
    Nodes = [Node]
      Node = atom()
    Name = atom()
    Request = term()
    Timeout = int()>=0 | infinity
    Result = {Replies,BadNodes}
      Replies = [{Node,Reply}]
        Reply = term()
      BadNodes = [Node]

 

  对所有在指定节点上被地面注册为Name的gen_server举办联合调用,通过第两遍发送请求到每个节点,然后等待复苏。那个gen_server进度将会调用Module:handle_call/3处理请求。

  
假如出现错误,函数也说不定回到错误元组{error,Error}。

  函数重临元组{Replies,BadNodes},其中,Replies是{Node,Reply}的列表,BadNodes是不设有节点的列表,或gen_server
Name不设有或从不回复。

 

  Nodes是请求被发送到的节点名称列表。默许值是中有着已知的节点列表[node()|nodes()]。

  
请注意,start_link函数,区其余一颦一笑模块满足上述的须求。

  Name是每个gen_server被地点注册的名目。

 

  Request是一个任意term,它看成内部的参数传递给Module:handle_call/3。

  
Restart定义什么日期停止的子进程应该被重启。一个permanent子进度应该总是被重启,一个temporary子进程没有被重启(即使当监督者的重启策略是rest_for_one或one_for_all和兄弟进程的挂掉导致temporary进程被为止),和一个transient子进度应该被重启仅当它那一个终止,也就是说,除过normal,shutdown或{shutdown,Term}的其余退出原因。

  提姆eout是一个不止零的整数,它指定多少微秒等待每个回复,原子infinity会无限期的等候。默认值是infinity。如果在指定时间内节点没有收到回复,该节点被投入到BadNodes。
当在节点Node来自gen_server回复Reply到达,{Node,Reply}被参加到Replies。Reply被定义在Module:handle_call/3的回来值里。

 

  为幸免随后的作答(在逾期之后)污染调用者的信息队列,一个当中人经过被用来做实在的调用。当它们到达一个悬停的进度,迟到的回复将不会被保留。

  
Shutdown定义子进度应该如何被终止。brutal_kill意味着子进程将被白白截止使用exit(Child,kill)。一个整数超时值意味着监督者将告诉子进度经过调用exit(Child,shutdown)来终止,然后以原因shutdown等待来自子进度的脱离信号。要是在指定数量皮秒内尚未接过退出信号,子进度使用exit(Child,kill)被白白截至。

cast(ServerRef, Request) -> ok
  Types:
  ServerRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()
    Node = atom()
    GlobalName = ViaName = term()
  Request = term()

 

  发送一个异步请求到引用名ServerRef的gen_server,然后随即赶回ok,假设目标节点或gen_server不存在,忽略新闻。gen_server将调用Module:handle_cast/2处理请求。

  
如若实进度是另一个监督者,Shutdown应该被设置成infinity,给子树充裕的时间关闭。假若实进度是劳力,它也被允许设置成infinity。

  参看call/2,3,了解ServerRef的描述。

 

  Request是一个任意term,它当作内部的参数传递给Module_cast/2。

  
警告:小心设置shutdown策略为infinity,当子进度是一个劳力。因为,在这种气象下,监控树的平息取决于子进度,它必须以安全的不二法门完成,它的清理进度必须回到。

abcast(Name, Request) -> abcast
abcast(Nodes, Name, Request) -> abcast
  Types:
    Nodes = [Node]
      Node = atom()
    Name = atom()
    Request = term()

 

  发送一个异步请求给在指定节点被本地注册为Name的gen_server。函数立刻赶回并且忽略不设有的节点,或gen_server
Name不存在。gen_server将调用Module:handle_cast/2处理请求。

  
请注意,所有子进程自动使用标准OTP行为模块落成基于关闭协议。

  参看 multi_call/2,3,4,精通参数描述。

 

reply(Client, Reply) -> Result
  Types:
    Reply = term()
    Result = term()

  
Type指定子进程是监督者照旧工笔者。

  当回复没有定义在Module:handle_call/3的归来值里,该函数可以被gen_server用来显式地发送过来给一个调用
call/2,3 或 multi_call/2,3,4的客户端。

 

  Client必须是提须要回调函数的From参数。Reply是一个任意term,它将作为call/2,3
或 multi_call/2,3,4的再次回到值被还原到客户端。

  
Modules被版本处理程序使用,在代码替换时期用于确定什么进程使用什么模块。作为一个经验法则,Modules应该一个元素列表[Module],其中,Module是回调模块,假设子进度是一个supervisor,
gen_server 或
gen_fsm。要是实进度是一个暗含回调模块集合的轩然大波管理器(gen_event),Modules应该是dynamic。关于版本控制的越多新闻参考OTP设计条件。

  重回Result没有被进一步定义,并且应该总是被忽视。

 

enter_loop(Module, Options, State)
enter_loop(Module, Options, State, ServerName)
enter_loop(Module, Options, State, Timeout)
enter_loop(Module, Options, State, ServerName, Timeout)
  Types:
    Module = atom()
    Options = [Option]
      Option = {debug,Dbgs}
        Dbgs = [Dbg]
          Dbg = trace | log | statistics | {log_to_file,FileName} | {install,{Func,FuncState}}
    State = term()
    ServerName = {local,Name} | {global,GlobalName} | {via,Module,ViaName}
      Name = atom()
      GlobalName = ViaName = term()
    Timeout = int() | infinity

  
内部地,监督者也跟踪子进程的长河号,或undefined借使没有经过号存在。

  使一个已存在的经过进入一个gen_server。不回来,反而那几个调用进度将跻身gen_server的吸纳循环,并变为一个gen_server进度。这么些历程必须采纳proc_lib的启航函数被启动。用户为该进程的别的开始化负责,包罗为它注册一个名字。

 

  这几个函数万分有用,当要求一个进一步错综复杂的初步化进度,而不是gen_server行为提供的。

数据类型

  Module,Option
和ServerName与调用gen_server:start[_link]/3,4所有同样的意思。不过,借使ServerName被指定,进度必须在该函数被调用前相应地被注册。

child() = undefined | pid()
child_id() = term() %% 不是pid()
child_spec() = 
     {Id :: child_id(),
      StartFunc :: mfargs(),
      Restart :: restart(),
      Shutdown :: shutdown(),
      Type :: worker(),
      Modules :: modules()}
    mfargs() = {M :: module(), F :: atom(), A :: [term()] | undefined} %% 如果Restart是temporary,A的值为undefined。
    modules() = [module()] | dynamic
    restart() = permanent | transient | temporary
    shutdown() = brutal_kill | timeout()
    strategy() = one_for_all | one_for_one | rest_for_one | simple_one_for_one
    sup_ref() = (Name :: atom())
          | {Name :: atom(), Node :: node()}
          | {global, Name :: atom()}
          | {via, Module :: module(), Name :: any()}
          | pid()
    worker() = worker | supervisor

  State和提姆(Tim)eout与Module:init/1的重返值有着相同的意义。回调模块Module也不必要导出一个init/1函数。

 

  退步:假使调用进程未被一个proc_lib函数启动,或者只要它未依照ServerName注册。

导出

回调函数

start_link(Module, Args) -> startlink_ret()
start_link(SupName, Module, Args) -> startlink_ret()
Types:
  SupName = sup_name()
  Module = module()
  Args = term()
  startlink_ret() = {ok, pid()} | ignore | {error, startlink_err()}
  startlink_err() = {already_started, pid()} | {shutdown, term()} | term()
    sup_name() = {local, Name :: atom()} | {global, Name :: atom()} | {via, Module :: module(), Name :: any()} 
Module:init(Args) -> Result
  Types:
    Args = term()
    Result = {ok,State} | {ok,State,Timeout} | {ok,State,hibernate} | {stop,Reason} | ignore
      State = term()
      Timeout = int()>=0 | infinity
      Reason = term()

  创造一个监督者进程作为监控树的一有的,在其他方面,函数将确保监督者链接到调用者进程(它的监督者)。

  无论什么日期一个gen_server使用gen_server:start/3,4 或
gen_server:start_link/3,4被启动,该函数被一个新进度调用去起初化。

 

  Args是提须要启动函数的参数。

  被创立的监督者进程调用Module:init/1找出重启策略、最大启动频率和子进度。为确保联合启动进程,start_link/2,3不会回来直到Module:init/1已经回到且所有子进程已被启动。

  假使开端化成功,函数应该回到{ok,State}, {ok,State,提姆eout} 或
{ok,State,hibernate},其中,State是gen_server的其中景观。

 

  假使一个平头超时值被提供,一个逾期将时有暴发,除非在提姆(Tim)eout微秒内接收一个伸手或新闻。一个超时被timeout原子标识,它应该被handle_info/2回调函数处理。infinity可以被用来无限期地等待,那是默认值。

  如若SupName={local,Name},supervisor使用register/2被登记为地点的Name。即便SupName={global,Name},supervisor使用global:register_name/2被注册为大局的Name。若是没有提供Name,supervisor不会被登记。即便SupName={via,Module,ViaName},supervisor将会用Module代表的注册表注册。Module回调应该导出函数register_name/2,
unregister_name/1, whereis_name/1 和
send/2,它们表现得像global模块对应的函数。由此,{via,global,Name}是一个实用地引用。

  假如hibernate被指定而不是一个超时值,进度将进入休眠当等待下一条音讯到达时(调用proc_lib:hibernate/3)。

 

  即使在初阶化时期出现错误,函数重临{stop,Reason},其中,Reason是别的term,或ignore。

  若是没有提供名称,监督者不会登记。

Module:handle_call(Request, From, State) -> Result
  Types:
    Request = term()
    From = {pid(),Tag}
    State = term()
    Result = {reply,Reply,NewState} | {reply,Reply,NewState,Timeout} | {reply,Reply,NewState,hibernate}
      | {noreply,NewState} | {noreply,NewState,Timeout} | {noreply,NewState,hibernate}
      | {stop,Reason,Reply,NewState} | {stop,Reason,NewState}
      Reply = term()
      NewState = term()
      Timeout = int()>=0 | infinity
      Reason = term()

 

  无论什么时候使用gen_server:call/2,3 或
gen_server:multi_call/2,3,4,gen_server接收请求发送,该函数被调用处理请求。

  Module是回调模块的称谓。

  Request是提需求call或multi_call的参数。

 

  From是一个元组{Pid,Tag},其中,Pid是客户端的进程号,Tag是一个唯一标志。

  Args是一个任意term,作为参数传递给Module:init/1。

  State是gen_server的里边景观。

 

  倘使函数再次回到{reply,Reply,NewState}, {reply,Reply,NewState,提姆(Tim)eout}
或 {reply,Reply,NewState,hibernate},Reply将被复苏给From作为call/2,3 或
multi_call/2,3,4的重回值。然后gen_server继续执行,可能更新内部景色NewState。参看Module:init/1通晓提姆(Tim)eout和hibernate的讲述。

  假诺监督者和它的子进程被成功成立,(也就是说,借使所有子进度启动函数再次来到{ok,Child},
{ok,Child,Info}, 或
ignore)函数重回{ok,Pid},其中Pid是监督者的进度号。假诺已存在指定SupName的过程,函数重临{error,{already_started,Pid}},其中,Pid是相当进程的进度号。

  尽管函数重临{noreply,NewState}, {noreply,NewState,提姆(Tim)eout} 或
{noreply,NewState,hibernate},gen_server将用NewState继续执行。任何对From的復苏必须显式使用gen_server:reply/2。

 

  要是函数返回{stop,Reason,Reply,NewState},Reply将恢复生机给From。假诺函数重回{stop,Reason,NewState},任何对From的死灰复燃必须显式使用gen_server:reply/2。然后,函数将调用Module:terminate(Reason,NewState),随后停下。

  如果Module:init/1再次回到ignore,该函数也回到ignore,而监督者以原因normal终止。即使Module:init/1失利或回到不科学的值,该函数再次来到{error,Term},其中,Term是带有关于错误音信的Term,监督者以原因Term终止。

Module:handle_cast(Request, State) -> Result
  Types:
    Request = term()
    State = term()
    Result = {noreply,NewState} | {noreply,NewState,Timeout} | {noreply,NewState,hibernate} | {stop,Reason,NewState}
      NewState = term()
      Timeout = int()>=0 | infinity
      Reason = term()

 

  无论什么时候,gen_server接收一个伸手发送使用gen_server:cast/2 或
gen_server:abcast/2,3,该函数被调用处理请求。

  倘若任何子进度启动函数是失败或重返一个错误元组或一个不当值,监督者首先将以原因shutdown终止所有已开行的进度,随后停下它和谐,然后重返{error,
{shutdown, Reason}}。

  参见Module:handle_call/3精通参数和可能重回值的讲述。

 

Module:handle_info(Info, State) -> Result
  Types:
    Info = timeout | term()
    State = term()
    Result = {noreply,NewState} | {noreply,NewState,Timeout} | {noreply,NewState,hibernate} | {stop,Reason,NewState}
      NewState = term()
      Timeout = int()>=0 | infinity
      Reason = normal | term()
start_child(SupRef, ChildSpec) -> startchild_ret()
Types:
  SupRef = sup_ref()
  ChildSpec = child_spec() | (List :: [term()])
  child_spec() = 
      {Id :: child_id(),
       StartFunc :: mfargs(),
       Restart :: restart(),
       Shutdown :: shutdown(),
       Type :: worker(),
       Modules :: modules()}
  startchild_ret() = {ok, Child :: child()} | {ok, Child :: child(), Info :: term()} | {error, startchild_err()}
  startchild_err() = already_present | {already_started, Child :: child()} | term()

  该函数被gen_server调用,当超时发生或接受到另外音信而不是同台或异步请求(或者系统新闻)。

  动态增添一个子正规到监督者SuperRef,它启动相应的子进度。

  Info是原子timeout,当超时发生,或是已吸收的消息。

  ServerRef可以是:

Module:terminate(Reason, State)
  Types:
    Reason = normal | shutdown | {shutdown,term()} | term()
    State = term()    

– 进程号;

Name,supervisor被本地注册的名称;
  • {Name,Node},supervisor在其余节点被地面注册;
  • {global,Name},supervisor被全局注册;
  • {via,Module,ViaName},supervisor通过代表的经过注册表注册。

 

  ChildSpec应该是卓有成效的子进度(除非该监督者是一个simple_one_for_one的监督者,看下边)。子进度将会动用定义在子规范的启动函数启动。

 

  如果是simple_one_for_one监督者的状态下,定义在Module:init/1的子规范将被拔取,ChildSpec应该是一个任意term列表。子进程将被启动通过添加List到已存在的起步函数参数,也就是说,通过调用apply(M,
F, A++List),其中,{M,F,A}是概念在子规范的启航函数。

 

  假使已经存在一个点名id的子规范,ChildSpec被舍弃,函数重回{error,already_present}
或 {error,{already_started,Child}},取决于对应的子进度是或不是运行。

 

  倘若实进程启动函数重返{ok,Child} 或
{ok,Child,Info},子规范和进度号被添加到监督者,函数重临相同的值。

  若是实进程启动函数重临ignore,子规范被添加到监督者,进度号安装为undefined,函数再次来到{ok,undefined}。

  若是实进度启动哈数重临一个错误元组或一个不当值,
或它败北,子规范被抛弃,函数重临{error,Error},其中Error是一个富含关于错误和子规范音讯的term。

 

terminate_child(SupRef, Id) -> Result
Types:
  SupRef = sup_ref()
  Id = pid() | child_id()
  Result = ok | {error, Error}
    Error = not_found | simple_one_for_one

  告诉监督者SupRef终止给定的子进度。

 

  即使监督者不是simple_one_for_one,Id必须是子规范标识符。进度被终止,倘诺有,除非它是temporary子进度,子规范被监督者保存。子进度随后可能被监督者重启。子进度也恐怕显式的通过调用restart_child/2被重启。使用delete_child/2移除子规范。

 

  即使实进度是temporary,进度一终止,子规范就被删去。那象征delete_child/2没有意义,restart_child/2不能用于这一个进程。

 

  借使监督者是simple_one_for_one,Id必须是子进程的pid(),借使指定的进度活着,但不是给定监督者的子进度,函数将重临{error,not_found}。借使给定子规范标识,而不是pid(),函数将赶回{error,simple_one_for_one}。

 

  如果成功,函数重临ok。如果没有点名Id的子规范,函数重回{error,not_found}。

 

  参考start_child/2了解SupRef的描述。

 

restart_child(SupRef, Id) -> Result
Types:
  SupRef = sup_ref()
  Id = child_id()
  Result = {ok, Child :: child()} | {ok, Child :: child(), Info :: term()} | {error, Error}
    Error = running | restarting | not_found | simple_one_for_one | term()

  告诉监督者SupRef重启一个子历程按照子规范标识符Id。子规范必须存在,对应子进度必须没有在运转。

 

  请留意temporary子进度,当子进度终止,子规范活动被剔除。随后,它不可以重启这么些子进度。

 

  参看start_child/2了解SupRef的描述。

 

  就算实规范标识Id不设有,函数再次来到{error,not_found}。即使实规范存在但相应进度已经运行,函数再次来到{error,running}。

 

  子进度启动函数再次来到{ok,Child} 或
{ok,Child,Info},进度号被添加到监督者,函数再次来到相同的值。

  子进度启动函数重返ignore,进度号仍然设置为undefined,函数重返{ok,undefined}。

  子进程启动函数再次回到一个漏洞万分多元组或一个张冠李戴值,或它失利,函数重临{error,Error},其中,Error是一个饱含错误信息的term。

 

which_children(SupRef) -> [{Id, Child, Type, Modules}]
Types:
  SupRef = sup_ref()
  Id = child_id() | undefined
  Child = child() | restarting
  Type = worker()
  Modules = modules()

  再次来到一个新创制列表,含有所有子规范和归属于监督者SupRef的子进度。

 

  请小心,在低内存状态下,监督大量子进度,调用该函数可能造成内存不足的非凡。

 

  参考start_child/2了解SupRef的描述。

 

  对于每个子规范/进程给出的新闻是:

  • Id –
    子规范中定义或在simple_one_for_one监督者情形下为undefined;
  • Child –
    对应子进度的历程号,函数将被重启为restarting或从不应该进程为undefined;
  • Type – 定义在子规范;
  • Modules – 定义在子规范。

 

count_children(SupRef) -> PropListOfCounts
Types:
  SupRef = sup_ref()
  PropListOfCounts = [Count]
  Count = {specs, ChildSpecCount :: integer() >= 0} | {active, ActiveProcessCount :: integer() >= 0}
       | {supervisors, ChildSupervisorCount :: integer() >= 0} | {workers, ChildWorkerCount :: integer() >= 0}

  重临一个特性列表,它包罗监督者子规范的下列元素和被管理的经过的多寡:

  •      specs –
    子进度活的或死的总数据;
  •      active –
    所有被监督者管理的激活的运转的子进度数量;
  •      supervisors –
    在正儿八经列表被标记为child_type =
    supervisor的所有子进度数量,不管仲进度是还是不是活着;
  •      workers –
    在标准列表被标记为child_type =
    worker的所有子进度数量,不管仲进度是或不是活着;

 

check_childspecs(ChildSpecs) -> Result
Types:
  ChildSpecs = [child_spec()]
  Result = ok | {error, Error :: term()}

  该函数必要一个子正经列表作为参数,如若他们在语法上都没错,重临ok,否则重回{error,Error}。

 

回调函数

Module:init(Args) -> Result
Types:
  Args = term()
  Result = {ok,{{RestartStrategy,MaxR,MaxT},[ChildSpec]}} | ignore
    RestartStrategy = strategy()
    MaxR = integer()>=0
    MaxT = integer()>0
    ChildSpec = child_spec()

  无论曾几何时使用supervisor:start_link/2,3
监督者被启动,函数被一个新的长河调用找出重启策略、最大重启频率和子规范。

 

  Args是提须要启动函数的参数。

 

  RestartStrategy是重启策略,马克斯(Max)R 和
马克斯T定义监督者的最大重启频率。
[ChildSpec]是一组有效地子规范,它定义哪些进程监督者应该启动和督察。参看下边关于监督规则的议论。

 

  请留心,当重启策略为simple_one_for_one,子规范列表必须只包括一个子正式列表(ID被忽略)。在开始化时期,没有子进度随后被启动,不过所有子进度被设定使用supervisor:start_child/2来动态启动。

 

  函数也可能回到ignore。

 

  

  翻译有题目的地点,请我们指正。

  该函数被gen_server调用,当它准备停止。它应有和Module:init/1相反,并做要求的清理。当它回到时,gen_server由于Reason终止。再次来到值被忽略。

  Reason是一个term,提出为止原因,State是gen_server的里边情形。

  Reason取决于gen_server终止的由来。若是因为另一个回调函数已经回到一个停下元组{stop,..},Reason将会有指定的值在非凡元组。假设是由于失败,Reason是错误原因。

  如果gen_server是监控树的一片段,并且被监控者有序终止,该函数将被调用,使用Reason=shutdown,即使运用以下情状:

  • gen_server已经安装为脱离信号;
  • 再者,被定义在监控者的子规范的闭馆策略是一个平头值,而不是brutal_kill。

  即使gen_server不是监控者的一片段,如果接到来自父进度的’EXIT’音信,函数将被调用。Reason将和’EXIT’信息无异于。

  否则,gen_server将随即停下。

  注意,除了normal,shutdown,或{shutdown,Term}的其余原因,gen_server被设定终止由于一个荒谬,并且采用error_logger:format/2报告一个不当。

Module:code_change(OldVsn, State, Extra) -> {ok, NewState} | {error, Reason}
  Types:
    OldVsn = Vsn | {down, Vsn}
      Vsn = term()
    State = NewState = term()
    Extra = term()
    Reason = term()

  该函数被gen_server调用,当它在本子升级/降级应该更新自己的中间景色,也就是说,当指令{update,Module,张煐e,…}在appup文件中被提交,其中Change={advanced,Extra}。参看OTP设计基准查看越多音讯。

  在晋级的景况下,OldVsn就是Vsn;在贬低的情形下,OldVsn就是{down,Vsn}。Vsn被回调模块Module的老版本的vsn属性定义。假如没有那样的性能定义,版本就是BEAM文件的校验和。

  State是gen_server的内部景观。

  Extra来自升级指令的{advanced,Extra}部分,被形容传递。

  假若成功,函数应该回到被更新的里边情形。

  假设函数重回{error,Reason},正在开展的升级将会失利,并且回滚到老版本。

Module:format_status(Opt, [PDict, State]) -> Status
  Types:
    Opt = normal | terminate
    PDict = [{Key, Value}]
    State = term()
    Status = term()

  请留心,该回调可选,所以回调模块不要求导出它,这么些回调模块提供一个默许完结,该函数重返回调模块状态。

  该函数被gen_server进度调用:

  • sys:get_status/1,2被调用获取gen_server状态。那种意况,Opt被设置成normal。
  • gem_server相当终止,生成错误日志。那种场所,Opt被设置成terminate。

  该函数是行得通的,对于那些境况定制gen_server的格式和表现。一个回调模块希望定制sys:get_status/1,2的再次来到值,和它在终止错误日志的状态突显,导出一个format_status/2实例,重返描述gen_server当前景观的term。

  PDict是gen_server的经过字典的眼前值。

  State是gen_server的中间景观。

  函数应该回到Status,定制当前情景的细节和gen_server的事态的term。在Status格式上从不任何限制,然而对于sys:get_status/1,2境况,对于Status提出的格式是[{data,
[{“State”,
Term}]}],其中,Term提供gen_server相关的底细。遵从这几个提出不是必须的,可是那样做将使回调模块的气象与sys:get_status/1,2的重返值一致。

  该函数的一个用法是回去紧凑的交替状态表示来避免有过大的情事项打印在日记里。

相关文章